i2o_scsi.c revision 3889b26bebd3e3cf5a3b95da683bab2f6462133d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2, or (at your option) any 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * later version. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For the avoidance of doubt the "preferred form" of this code is one which 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is in an open non patent encumbered format. Where cryptographic key signing 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forms part of the process of creating an executable the information 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including keys needed to generate an equivalently functional executable 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are deemed to be part of the source code. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complications for I2O scsi 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Each (bus,lun) is a logical device in I2O. We keep a map 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * table. We spoof failed selection for unmapped units 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Request sense buffers can come back for free. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Scatter gather is a bit dynamic. We have to investigate at 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setup time. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Some of our resources are dynamically shared. The i2o core 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * needs a message reservation protocol to avoid swap v net 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * deadlocking. We need to back off queue requests. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In general the firmware wants to help. Where its help isn't performance 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * useful we just ignore the aid. Its not worth the code in truth. 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes/additions: 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Steve Ralston: 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Scatter gather now works 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Markus Lidel <Markus.Lidel@shadowconnect.com>: 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Minor fixes for 2.6. 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To Do: 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 64bit cleanups 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fix the resource management problems. 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/prefetch.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2o.h> 57b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#include <linux/scatterlist.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atomic.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h> 68b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#include <scsi/sg.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OSM_NAME "scsi-osm" 712e1973a3cd0b9fe31469be62df3583bdc5a34f51Markus Lidel#define OSM_VERSION "1.316" 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OSM_DESCRIPTION "I2O SCSI Peripheral OSM" 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_driver i2o_scsi_driver; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidelstatic unsigned int i2o_scsi_max_id = 16; 77b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidelstatic unsigned int i2o_scsi_max_lun = 255; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct i2o_scsi_host { 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *scsi_host; /* pointer to the SCSI host */ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *iop; /* pointer to the I2O controller */ 82b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel unsigned int lun; /* lun's used for block devices */ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template i2o_scsi_host_template; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2O_SCSI_CAN_QUEUE 4 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCSI OSM class handling definition */ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_class_id i2o_scsi_class_id[] = { 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {I2O_CLASS_SCSI_PERIPHERAL}, 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {I2O_CLASS_END} 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_scsi_host *i2o_shost; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *scsi_host; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_channel = 0; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 type; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size; 105b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u16 body_size = 6; 106b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 107b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC 108b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (c->adaptec) 109b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel body_size = 8; 110b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(i2o_dev, &c->devices, list) 113f10378fff658f61307496e0ae00095041725cf07Markus Lidel if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) { 114793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) 115b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel && (type == 0x01)) /* SCSI bus */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_channel++; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!max_channel) { 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_warn("no channels found on %s\n", c->name); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-EFAULT); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = max_channel * sizeof(struct i2o_device *) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds + sizeof(struct i2o_scsi_host); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!scsi_host) { 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_warn("Could not allocate SCSI host\n"); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host->max_channel = max_channel - 1; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host->max_id = i2o_scsi_max_id; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host->max_lun = i2o_scsi_max_lun; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host->this_id = c->unit; 137b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost->scsi_host = scsi_host; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost->iop = c; 142b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel i2o_shost->lun = 1; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(i2o_dev, &c->devices, list) 146f10378fff658f61307496e0ae00095041725cf07Markus Lidel if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) { 147793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) 148b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel && (type == 0x01)) /* only SCSI bus */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost->channel[i++] = i2o_dev; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i >= max_channel) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i2o_shost; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_get_host - Get an I2O SCSI host 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @c: I2O controller to for which to get the SCSI host 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the I2O controller already exists as SCSI host, the SCSI host 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is returned, otherwise the I2O controller is added to the SCSI 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * core. 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns pointer to the I2O SCSI host on success or NULL on failure. 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return c->driver_data[i2o_scsi_driver.context]; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_remove - Remove I2O device from SCSI core 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: device which should be removed 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Removes the I2O device from the SCSI core again. 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success. 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_remove(struct device *dev) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev = to_i2o_device(dev); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *c = i2o_dev->iop; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_scsi_host *i2o_shost; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_device *scsi_dev; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid); 189f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost = i2o_scsi_get_host(c); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shost_for_each_device(scsi_dev, i2o_shost->scsi_host) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (scsi_dev->hostdata == i2o_dev) { 194f10378fff658f61307496e0ae00095041725cf07Markus Lidel sysfs_remove_link(&i2o_dev->device.kobj, "scsi"); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_remove_device(scsi_dev); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_device_put(scsi_dev); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: device to verify if it is a I2O SCSI device 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Retrieve channel, id and lun for I2O device. If everthing goes well 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register the I2O device as SCSI device on the I2O SCSI controller. 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success or negative error code on failure. 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_probe(struct device *dev) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev = to_i2o_device(dev); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *c = i2o_dev->iop; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_scsi_host *i2o_shost; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *scsi_host; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *parent; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_device *scsi_dev; 220b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u32 id = -1; 221b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u64 lun = -1; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int channel = -1; 2233889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik int i, rc; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost = i2o_scsi_get_host(c); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i2o_shost) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host = i2o_shost->scsi_host; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel switch (i2o_dev->lct_data.class_id) { 232b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel case I2O_CLASS_RANDOM_BLOCK_STORAGE: 233b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel case I2O_CLASS_EXECUTIVE: 234b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC 235b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (c->adaptec) { 236b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u8 type; 237b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel struct i2o_device *d = i2o_shost->channel[0]; 238b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 239793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1) 240b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel && (type == 0x01)) /* SCSI bus */ 241793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) { 242b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel channel = 0; 243b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (i2o_dev->lct_data.class_id == 244b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel I2O_CLASS_RANDOM_BLOCK_STORAGE) 245793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel lun = 246793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel cpu_to_le64(i2o_shost-> 247793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel lun++); 248b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel else 249b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel lun = 0; 250b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 251b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 252b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif 253b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel break; 254b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 255b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel case I2O_CLASS_SCSI_PERIPHERAL: 256793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4)) 257b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel return -EFAULT; 258b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 259793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8)) 260b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel return -EFAULT; 261b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 262b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid); 263b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (!parent) { 264b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel osm_warn("can not find parent of device %03x\n", 265b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel i2o_dev->lct_data.tid); 266b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel return -EFAULT; 267b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 268b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 269b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++) 270b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (i2o_shost->channel[i] == parent) 271b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel channel = i; 272b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel break; 273b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 274b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel default: 275b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel return -EFAULT; 276b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 277b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 278b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (channel == -1) { 279b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel osm_warn("can not find channel of device %03x\n", 280b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel i2o_dev->lct_data.tid); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 282b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 284793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (le32_to_cpu(id) >= scsi_host->max_id) { 285793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)", 286793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel le32_to_cpu(id), scsi_host->max_id); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 290793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel if (le64_to_cpu(lun) >= scsi_host->max_lun) { 291793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel osm_warn("SCSI device lun (%lu) >= max_lun of I2O host (%d)", 292793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel (long unsigned int)le64_to_cpu(lun), 293793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel scsi_host->max_lun); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_dev = 298793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id), 299793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel le64_to_cpu(lun), i2o_dev); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301f10378fff658f61307496e0ae00095041725cf07Markus Lidel if (IS_ERR(scsi_dev)) { 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_warn("can not add SCSI device %03x\n", 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_dev->lct_data.tid); 304f10378fff658f61307496e0ae00095041725cf07Markus Lidel return PTR_ERR(scsi_dev); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3073889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik rc = sysfs_create_link(&i2o_dev->device.kobj, 3083889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik &scsi_dev->sdev_gendev.kobj, "scsi"); 3093889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik if (rc) 3103889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik goto err; 311f10378fff658f61307496e0ae00095041725cf07Markus Lidel 312dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %ld\n", 313793fd15d9fafe5b1c71e50d3c041f1463895dbdeMarkus Lidel i2o_dev->lct_data.tid, channel, le32_to_cpu(id), 314dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel (long unsigned int)le64_to_cpu(lun)); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3173889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik 3183889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzikerr: 3193889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik scsi_remove_device(scsi_dev); 3203889b26bebd3e3cf5a3b95da683bab2f6462133dJeff Garzik return rc; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *i2o_scsi_info(struct Scsi_Host *SChost) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_scsi_host *hostdata; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hostdata = (struct i2o_scsi_host *)SChost->hostdata; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return hostdata->iop->name; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_reply - SCSI OSM message reply handler 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @c: controller issuing the reply 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @m: message id for flushing 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @msg: the message from the controller 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process reply messages (interrupts in normal scsi controller think). 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can get a variety of messages to process. The normal path is 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scsi command completions. We must also deal with IOP failures, 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the reply to a bus reset and the reply to a LUN query. 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success and if the reply should not be flushed or > 0 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on success and if the reply should be flushed. Returns negative error 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * code on failure and if the reply should be flushed. 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_reply(struct i2o_controller *c, u32 m, 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_message *msg) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cmd; 3499e87545f06930c1d294423a8091d1077e7444a47Markus Lidel u32 error; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct device *dev; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt)); 3539e87545f06930c1d294423a8091d1077e7444a47Markus Lidel if (unlikely(!cmd)) { 3549e87545f06930c1d294423a8091d1077e7444a47Markus Lidel osm_err("NULL reply received!\n"); 3559e87545f06930c1d294423a8091d1077e7444a47Markus Lidel return -1; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Low byte is device status, next is adapter status, 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (then one byte reserved), then request status. 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3629e87545f06930c1d294423a8091d1077e7444a47Markus Lidel error = le32_to_cpu(msg->body[0]); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3649e87545f06930c1d294423a8091d1077e7444a47Markus Lidel osm_debug("Completed %ld\n", cmd->serial_number); 3659e87545f06930c1d294423a8091d1077e7444a47Markus Lidel 3669e87545f06930c1d294423a8091d1077e7444a47Markus Lidel cmd->result = error & 0xff; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3689e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let 3699e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * the SCSI layer handle the error 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3719e87545f06930c1d294423a8091d1077e7444a47Markus Lidel if (cmd->result) 3729e87545f06930c1d294423a8091d1077e7444a47Markus Lidel memcpy(cmd->sense_buffer, &msg->body[3], 3739e87545f06930c1d294423a8091d1077e7444a47Markus Lidel min(sizeof(cmd->sense_buffer), (size_t) 40)); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3759e87545f06930c1d294423a8091d1077e7444a47Markus Lidel /* only output error code if AdapterStatus is not HBA_SUCCESS */ 3769e87545f06930c1d294423a8091d1077e7444a47Markus Lidel if ((error >> 8) & 0xff) 3779e87545f06930c1d294423a8091d1077e7444a47Markus Lidel osm_err("SCSI error %08x\n", error); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3799e87545f06930c1d294423a8091d1077e7444a47Markus Lidel dev = &c->pdev->dev; 3809e87545f06930c1d294423a8091d1077e7444a47Markus Lidel if (cmd->use_sg) 3819e87545f06930c1d294423a8091d1077e7444a47Markus Lidel dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg, 3829e87545f06930c1d294423a8091d1077e7444a47Markus Lidel cmd->sc_data_direction); 3839e87545f06930c1d294423a8091d1077e7444a47Markus Lidel else if (cmd->SCp.dma_handle) 3849e87545f06930c1d294423a8091d1077e7444a47Markus Lidel dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen, 3859e87545f06930c1d294423a8091d1077e7444a47Markus Lidel cmd->sc_data_direction); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3879e87545f06930c1d294423a8091d1077e7444a47Markus Lidel cmd->scsi_done(cmd); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3899e87545f06930c1d294423a8091d1077e7444a47Markus Lidel return 1; 3909e87545f06930c1d294423a8091d1077e7444a47Markus Lidel}; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3929e87545f06930c1d294423a8091d1077e7444a47Markus Lidel/** 3939e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * i2o_scsi_notify_device_add - Retrieve notifications of added devices 3949e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * @i2o_dev: the I2O device which was added 3959e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * 3969e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * If a I2O device is added we catch the notification, because I2O classes 3979e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * other then SCSI peripheral will not be received through 3989e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * i2o_scsi_probe(). 3999e87545f06930c1d294423a8091d1077e7444a47Markus Lidel */ 4009e87545f06930c1d294423a8091d1077e7444a47Markus Lidelstatic void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev) 4019e87545f06930c1d294423a8091d1077e7444a47Markus Lidel{ 4029e87545f06930c1d294423a8091d1077e7444a47Markus Lidel switch (i2o_dev->lct_data.class_id) { 4039e87545f06930c1d294423a8091d1077e7444a47Markus Lidel case I2O_CLASS_EXECUTIVE: 4049e87545f06930c1d294423a8091d1077e7444a47Markus Lidel case I2O_CLASS_RANDOM_BLOCK_STORAGE: 4059e87545f06930c1d294423a8091d1077e7444a47Markus Lidel i2o_scsi_probe(&i2o_dev->device); 4069e87545f06930c1d294423a8091d1077e7444a47Markus Lidel break; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4089e87545f06930c1d294423a8091d1077e7444a47Markus Lidel default: 4099e87545f06930c1d294423a8091d1077e7444a47Markus Lidel break; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4119e87545f06930c1d294423a8091d1077e7444a47Markus Lidel}; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4139e87545f06930c1d294423a8091d1077e7444a47Markus Lidel/** 4149e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * i2o_scsi_notify_device_remove - Retrieve notifications of removed 4159e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * devices 4169e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * @i2o_dev: the I2O device which was removed 4179e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * 4189e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * If a I2O device is removed, we catch the notification to remove the 4199e87545f06930c1d294423a8091d1077e7444a47Markus Lidel * corresponding SCSI device. 4209e87545f06930c1d294423a8091d1077e7444a47Markus Lidel */ 4219e87545f06930c1d294423a8091d1077e7444a47Markus Lidelstatic void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev) 4229e87545f06930c1d294423a8091d1077e7444a47Markus Lidel{ 4239e87545f06930c1d294423a8091d1077e7444a47Markus Lidel switch (i2o_dev->lct_data.class_id) { 4249e87545f06930c1d294423a8091d1077e7444a47Markus Lidel case I2O_CLASS_EXECUTIVE: 4259e87545f06930c1d294423a8091d1077e7444a47Markus Lidel case I2O_CLASS_RANDOM_BLOCK_STORAGE: 4269e87545f06930c1d294423a8091d1077e7444a47Markus Lidel i2o_scsi_remove(&i2o_dev->device); 4279e87545f06930c1d294423a8091d1077e7444a47Markus Lidel break; 428f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel 4299e87545f06930c1d294423a8091d1077e7444a47Markus Lidel default: 4309e87545f06930c1d294423a8091d1077e7444a47Markus Lidel break; 4319e87545f06930c1d294423a8091d1077e7444a47Markus Lidel } 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_notify_controller_add - Retrieve notifications of added 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controllers 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @c: the controller which was added 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a I2O controller is added, we catch the notification to add a 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * corresponding Scsi_Host. 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i2o_scsi_notify_controller_add(struct i2o_controller *c) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_scsi_host *i2o_shost; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost = i2o_scsi_host_alloc(c); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(i2o_shost)) { 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_err("Could not initialize SCSI host\n"); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = scsi_add_host(i2o_shost->scsi_host, &c->device); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) { 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_err("Could not add SCSI host\n"); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host_put(i2o_shost->scsi_host); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c->driver_data[i2o_scsi_driver.context] = i2o_shost; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_debug("new I2O SCSI host added\n"); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_notify_controller_remove - Retrieve notifications of removed 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controllers 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @c: the controller which was removed 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a I2O controller is removed, we catch the notification to remove the 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * corresponding Scsi_Host. 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void i2o_scsi_notify_controller_remove(struct i2o_controller *c) 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_scsi_host *i2o_shost; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_shost = i2o_scsi_get_host(c); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i2o_shost) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c->driver_data[i2o_scsi_driver.context] = NULL; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_remove_host(i2o_shost->scsi_host); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host_put(i2o_shost->scsi_host); 484f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("I2O SCSI host removed\n"); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCSI OSM driver struct */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_driver i2o_scsi_driver = { 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = OSM_NAME, 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .reply = i2o_scsi_reply, 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .classes = i2o_scsi_class_id, 4929e87545f06930c1d294423a8091d1077e7444a47Markus Lidel .notify_device_add = i2o_scsi_notify_device_add, 4939e87545f06930c1d294423a8091d1077e7444a47Markus Lidel .notify_device_remove = i2o_scsi_notify_device_remove, 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .notify_controller_add = i2o_scsi_notify_controller_add, 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .notify_controller_remove = i2o_scsi_notify_controller_remove, 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = i2o_scsi_probe, 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = i2o_scsi_remove, 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_queuecommand - queue a SCSI command 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @SCpnt: scsi command pointer 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @done: callback for completion 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Issue a scsi command asynchronously. Return 0 on success or 1 if 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we hit an error (normally message queue congestion). The only 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * minor complication here is that I2O deals with the device addressing 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we have to map the bus/dev/lun back to an I2O handle as well 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as faking absent devices ourself. 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Locks: takes the controller lock on error path only 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*done) (struct scsi_cmnd *)) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *c; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tid; 522a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel struct i2o_message *msg; 523f10378fff658f61307496e0ae00095041725cf07Markus Lidel /* 524f10378fff658f61307496e0ae00095041725cf07Markus Lidel * ENABLE_DISCONNECT 525f10378fff658f61307496e0ae00095041725cf07Markus Lidel * SIMPLE_TAG 526f10378fff658f61307496e0ae00095041725cf07Markus Lidel * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME 527f10378fff658f61307496e0ae00095041725cf07Markus Lidel */ 528f10378fff658f61307496e0ae00095041725cf07Markus Lidel u32 scsi_flags = 0x20a00000; 529b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u32 sgl_offset; 530a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel u32 *mptr; 531b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u32 cmd = I2O_CMD_SCSI_EXEC << 24; 532b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel int rc = 0; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Do the incoming paperwork 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_dev = SCpnt->device->hostdata; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = i2o_dev->iop; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->scsi_done = done; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(!i2o_dev)) { 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_warn("no I2O device in request\n"); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->result = DID_NO_CONNECT << 16; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done(SCpnt); 546b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel goto exit; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid = i2o_dev->lct_data.tid; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_debug("qcmd: Tid = %03x\n", tid); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_debug("Real scsi messages.\n"); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put together a scsi execscb message 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (SCpnt->sc_data_direction) { 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PCI_DMA_NONE: 559f10378fff658f61307496e0ae00095041725cf07Markus Lidel /* DATA NO XFER */ 560b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel sgl_offset = SGL_OFFSET_0; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PCI_DMA_TODEVICE: 564f10378fff658f61307496e0ae00095041725cf07Markus Lidel /* DATA OUT (iop-->dev) */ 565f10378fff658f61307496e0ae00095041725cf07Markus Lidel scsi_flags |= 0x80000000; 566b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel sgl_offset = SGL_OFFSET_10; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PCI_DMA_FROMDEVICE: 570f10378fff658f61307496e0ae00095041725cf07Markus Lidel /* DATA IN (iop<--dev) */ 571f10378fff658f61307496e0ae00095041725cf07Markus Lidel scsi_flags |= 0x40000000; 572b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel sgl_offset = SGL_OFFSET_10; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unknown - kill the command */ 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->result = DID_NO_CONNECT << 16; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done(SCpnt); 579b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel goto exit; 580b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 581b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 582b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel /* 583b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel * Obtain an I2O message. If there are none free then 584b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel * throw it back to the scsi layer 585b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel */ 586b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 587a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg = i2o_msg_get(c); 588a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel if (IS_ERR(msg)) { 589b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel rc = SCSI_MLQUEUE_HOST_BUSY; 590b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel goto exit; 591b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 592b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 593b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel mptr = &msg->body[0]; 594b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 595beb40487508290f5d6565598c60a3f44261beef2Christoph Hellwig#if 0 /* this code can't work */ 596b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC 597b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (c->adaptec) { 598b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel u32 adpt_flags = 0; 599b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 600b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) { 601b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel i2o_sg_io_hdr_t __user *usr_ptr = 602b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel ((Sg_request *) (SCpnt->sc_request-> 603b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel upper_private_data))->header. 604b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel usr_ptr; 605b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 606b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (usr_ptr) 607b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel get_user(adpt_flags, &usr_ptr->flags); 608b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 609b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 610b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel switch (i2o_dev->lct_data.class_id) { 611b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel case I2O_CLASS_EXECUTIVE: 612b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel case I2O_CLASS_RANDOM_BLOCK_STORAGE: 613b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel /* interpret flag has to be set for executive */ 614b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET; 615b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel break; 616b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 617b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel default: 618b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel break; 619b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } 620b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 621b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel /* 622b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel * for Adaptec controllers we use the PRIVATE command, because 623b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel * the normal SCSI EXEC doesn't support all SCSI commands on 624b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel * all controllers (for example READ CAPACITY). 625b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel */ 626b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (sgl_offset == SGL_OFFSET_10) 627b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel sgl_offset = SGL_OFFSET_12; 628b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel cmd = I2O_CMD_PRIVATE << 24; 629a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC); 630a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel *mptr++ = cpu_to_le32(adpt_flags | tid); 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 632b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif 633beb40487508290f5d6565598c60a3f44261beef2Christoph Hellwig#endif 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 635a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); 636a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We want the SCSI control block back */ 639a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt)); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* LSI_920_PCI_QUIRK 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Intermittant observations of msg frame word data corruption 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * observed on msg[4] after: 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WRITE, READ-MODIFY-WRITE 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * operations. 19990606 -sralston 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (Hence we build this word via tag. Its good practice anyway 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we don't want fetches over PCI needlessly) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attach tags to the devices */ 6539e87545f06930c1d294423a8091d1077e7444a47Markus Lidel /* FIXME: implement 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(SCpnt->device->tagged_supported) { 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(SCpnt->tag == HEAD_OF_QUEUE_TAG) 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_flags |= 0x01000000; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if(SCpnt->tag == ORDERED_QUEUE_TAG) 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_flags |= 0x01800000; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 662a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel *mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write SCSI command into the message - always 16 byte block */ 665a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel memcpy(mptr, SCpnt->cmnd, 16); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mptr += 4; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 668b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (sgl_offset != SGL_OFFSET_0) { 669b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel /* write size of data addressed by SGL */ 670a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel *mptr++ = cpu_to_le32(SCpnt->request_bufflen); 671b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 672b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel /* Now fill in the SGList and command */ 673b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (SCpnt->use_sg) { 674b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (!i2o_dma_map_sg(c, SCpnt->request_buffer, 675b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel SCpnt->use_sg, 676b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel SCpnt->sc_data_direction, &mptr)) 677b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel goto nomem; 678b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel } else { 679b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel SCpnt->SCp.dma_handle = 680b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel i2o_dma_map_single(c, SCpnt->request_buffer, 681b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel SCpnt->request_bufflen, 682b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel SCpnt->sc_data_direction, &mptr); 683b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel if (dma_mapping_error(SCpnt->SCp.dma_handle)) 684b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel goto nomem; 685f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel } 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Stick the headers on */ 689a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->u.head[0] = 690a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Queue the message */ 693a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel i2o_msg_post(c, msg); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_debug("Issued %ld\n", SCpnt->serial_number); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 698b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 699b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel nomem: 700b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel rc = -ENOMEM; 701a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel i2o_msg_nop(c, msg); 702b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel 703b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel exit: 704b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel return rc; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_abort - abort a running command 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @SCpnt: command to abort 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ask the I2O controller to abort a command. This is an asynchrnous 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * process and our callback handler will see the command complete with an 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aborted message if it succeeds. 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 if the command is successfully aborted or negative error code 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on failure. 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_abort(struct scsi_cmnd *SCpnt) 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *c; 722a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel struct i2o_message *msg; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tid; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = FAILED; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_warn("Aborting command block.\n"); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_dev = SCpnt->device->hostdata; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = i2o_dev->iop; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tid = i2o_dev->lct_data.tid; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 732a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); 733a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel if (IS_ERR(msg)) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 736a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0); 737a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->u.head[1] = 738a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid); 739a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt)); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741e22bec266cd6f540da2a61db216914c3473135ccMarkus Lidel if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT)) 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = SUCCESS; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_bios_param - Invent disk geometry 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @sdev: scsi device 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: block layer device 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @capacity: size in sectors 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @ip: geometry array 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is anyones guess quite frankly. We use the same rules everyone 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * else appears to and hope. It seems to work. 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_scsi_bios_param(struct scsi_device *sdev, 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *dev, sector_t capacity, 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *ip) 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = capacity; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 64; /* heads */ 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 32; /* sectors */ 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 255; /* heads */ 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 63; /* sectors */ 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = size / (255 * 63); /* cylinders */ 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template i2o_scsi_host_template = { 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_name = OSM_NAME, 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = OSM_DESCRIPTION, 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .info = i2o_scsi_info, 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queuecommand = i2o_scsi_queuecommand, 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .eh_abort_handler = i2o_scsi_abort, 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bios_param = i2o_scsi_bios_param, 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .can_queue = I2O_SCSI_CAN_QUEUE, 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .sg_tablesize = 8, 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cmd_per_lun = 6, 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .use_clustering = ENABLE_CLUSTERING, 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_init - SCSI OSM initialization function 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register SCSI OSM into I2O core. 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success or negative error code on failure. 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init i2o_scsi_init(void) 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register SCSI OSM into I2O core */ 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = i2o_driver_register(&i2o_scsi_driver); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) { 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds osm_err("Could not register SCSI driver\n"); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_scsi_exit - SCSI OSM exit function 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unregisters SCSI OSM from I2O core. 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit i2o_scsi_exit(void) 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unregister I2O SCSI OSM from I2O core */ 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_unregister(&i2o_scsi_driver); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Red Hat Software"); 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(OSM_DESCRIPTION); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(OSM_VERSION); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(i2o_scsi_init); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(i2o_scsi_exit); 829