| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * This program is free software; you can redistribute it and/or modify it | 
 | 3 |  * under the terms of the GNU General Public License as published by the | 
 | 4 |  * Free Software Foundation; either version 2, or (at your option) any | 
 | 5 |  * later version. | 
 | 6 |  * | 
 | 7 |  * This program is distributed in the hope that it will be useful, but | 
 | 8 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 9 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 10 |  * General Public License for more details. | 
 | 11 |  * | 
 | 12 |  * For the avoidance of doubt the "preferred form" of this code is one which | 
 | 13 |  * is in an open non patent encumbered format. Where cryptographic key signing | 
 | 14 |  * forms part of the process of creating an executable the information | 
 | 15 |  * including keys needed to generate an equivalently functional executable | 
 | 16 |  * are deemed to be part of the source code. | 
 | 17 |  * | 
 | 18 |  *  Complications for I2O scsi | 
 | 19 |  * | 
 | 20 |  *	o	Each (bus,lun) is a logical device in I2O. We keep a map | 
 | 21 |  *		table. We spoof failed selection for unmapped units | 
 | 22 |  *	o	Request sense buffers can come back for free. | 
 | 23 |  *	o	Scatter gather is a bit dynamic. We have to investigate at | 
 | 24 |  *		setup time. | 
 | 25 |  *	o	Some of our resources are dynamically shared. The i2o core | 
 | 26 |  *		needs a message reservation protocol to avoid swap v net | 
 | 27 |  *		deadlocking. We need to back off queue requests. | 
 | 28 |  * | 
 | 29 |  *	In general the firmware wants to help. Where its help isn't performance | 
 | 30 |  *	useful we just ignore the aid. Its not worth the code in truth. | 
 | 31 |  * | 
 | 32 |  * Fixes/additions: | 
 | 33 |  *	Steve Ralston: | 
 | 34 |  *		Scatter gather now works | 
 | 35 |  *	Markus Lidel <Markus.Lidel@shadowconnect.com>: | 
 | 36 |  *		Minor fixes for 2.6. | 
 | 37 |  * | 
 | 38 |  * To Do: | 
 | 39 |  *	64bit cleanups | 
 | 40 |  *	Fix the resource management problems. | 
 | 41 |  */ | 
 | 42 |  | 
 | 43 | #include <linux/module.h> | 
 | 44 | #include <linux/kernel.h> | 
 | 45 | #include <linux/types.h> | 
 | 46 | #include <linux/string.h> | 
 | 47 | #include <linux/ioport.h> | 
 | 48 | #include <linux/jiffies.h> | 
 | 49 | #include <linux/interrupt.h> | 
 | 50 | #include <linux/timer.h> | 
 | 51 | #include <linux/delay.h> | 
 | 52 | #include <linux/proc_fs.h> | 
 | 53 | #include <linux/prefetch.h> | 
 | 54 | #include <linux/pci.h> | 
 | 55 | #include <linux/blkdev.h> | 
 | 56 | #include <linux/i2o.h> | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 57 | #include <linux/scatterlist.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 |  | 
 | 59 | #include <asm/dma.h> | 
 | 60 | #include <asm/system.h> | 
 | 61 | #include <asm/io.h> | 
 | 62 | #include <asm/atomic.h> | 
 | 63 |  | 
 | 64 | #include <scsi/scsi.h> | 
 | 65 | #include <scsi/scsi_host.h> | 
 | 66 | #include <scsi/scsi_device.h> | 
 | 67 | #include <scsi/scsi_cmnd.h> | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 68 | #include <scsi/sg.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 |  | 
 | 70 | #define OSM_NAME	"scsi-osm" | 
| Markus Lidel | 2e1973a | 2006-01-06 00:19:32 -0800 | [diff] [blame] | 71 | #define OSM_VERSION	"1.316" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | #define OSM_DESCRIPTION	"I2O SCSI Peripheral OSM" | 
 | 73 |  | 
 | 74 | static struct i2o_driver i2o_scsi_driver; | 
 | 75 |  | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 76 | static unsigned int i2o_scsi_max_id = 16; | 
 | 77 | static unsigned int i2o_scsi_max_lun = 255; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 |  | 
 | 79 | struct i2o_scsi_host { | 
 | 80 | 	struct Scsi_Host *scsi_host;	/* pointer to the SCSI host */ | 
 | 81 | 	struct i2o_controller *iop;	/* pointer to the I2O controller */ | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 82 | 	unsigned int lun;	/* lun's used for block devices */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | 	struct i2o_device *channel[0];	/* channel->i2o_dev mapping table */ | 
 | 84 | }; | 
 | 85 |  | 
 | 86 | static struct scsi_host_template i2o_scsi_host_template; | 
 | 87 |  | 
 | 88 | #define I2O_SCSI_CAN_QUEUE	4 | 
 | 89 |  | 
 | 90 | /* SCSI OSM class handling definition */ | 
 | 91 | static struct i2o_class_id i2o_scsi_class_id[] = { | 
 | 92 | 	{I2O_CLASS_SCSI_PERIPHERAL}, | 
 | 93 | 	{I2O_CLASS_END} | 
 | 94 | }; | 
 | 95 |  | 
 | 96 | static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c) | 
 | 97 | { | 
 | 98 | 	struct i2o_scsi_host *i2o_shost; | 
 | 99 | 	struct i2o_device *i2o_dev; | 
 | 100 | 	struct Scsi_Host *scsi_host; | 
 | 101 | 	int max_channel = 0; | 
 | 102 | 	u8 type; | 
 | 103 | 	int i; | 
 | 104 | 	size_t size; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 105 | 	u16 body_size = 6; | 
 | 106 |  | 
 | 107 | #ifdef CONFIG_I2O_EXT_ADAPTEC | 
 | 108 | 	if (c->adaptec) | 
 | 109 | 		body_size = 8; | 
 | 110 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 |  | 
 | 112 | 	list_for_each_entry(i2o_dev, &c->devices, list) | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 113 | 	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) { | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 114 | 		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 115 | 		    && (type == 0x01))	/* SCSI bus */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | 			max_channel++; | 
 | 117 | 	} | 
 | 118 |  | 
 | 119 | 	if (!max_channel) { | 
 | 120 | 		osm_warn("no channels found on %s\n", c->name); | 
 | 121 | 		return ERR_PTR(-EFAULT); | 
 | 122 | 	} | 
 | 123 |  | 
 | 124 | 	size = max_channel * sizeof(struct i2o_device *) | 
 | 125 | 	    + sizeof(struct i2o_scsi_host); | 
 | 126 |  | 
 | 127 | 	scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size); | 
 | 128 | 	if (!scsi_host) { | 
 | 129 | 		osm_warn("Could not allocate SCSI host\n"); | 
 | 130 | 		return ERR_PTR(-ENOMEM); | 
 | 131 | 	} | 
 | 132 |  | 
 | 133 | 	scsi_host->max_channel = max_channel - 1; | 
 | 134 | 	scsi_host->max_id = i2o_scsi_max_id; | 
 | 135 | 	scsi_host->max_lun = i2o_scsi_max_lun; | 
 | 136 | 	scsi_host->this_id = c->unit; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 137 | 	scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 |  | 
 | 139 | 	i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata; | 
 | 140 | 	i2o_shost->scsi_host = scsi_host; | 
 | 141 | 	i2o_shost->iop = c; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 142 | 	i2o_shost->lun = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 |  | 
 | 144 | 	i = 0; | 
 | 145 | 	list_for_each_entry(i2o_dev, &c->devices, list) | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 146 | 	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) { | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 147 | 		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 148 | 		    && (type == 0x01))	/* only SCSI bus */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 | 			i2o_shost->channel[i++] = i2o_dev; | 
 | 150 |  | 
 | 151 | 		if (i >= max_channel) | 
 | 152 | 			break; | 
 | 153 | 	} | 
 | 154 |  | 
 | 155 | 	return i2o_shost; | 
 | 156 | }; | 
 | 157 |  | 
 | 158 | /** | 
 | 159 |  *	i2o_scsi_get_host - Get an I2O SCSI host | 
 | 160 |  *	@c: I2O controller to for which to get the SCSI host | 
 | 161 |  * | 
 | 162 |  *	If the I2O controller already exists as SCSI host, the SCSI host | 
 | 163 |  *	is returned, otherwise the I2O controller is added to the SCSI | 
 | 164 |  *	core. | 
 | 165 |  * | 
 | 166 |  *	Returns pointer to the I2O SCSI host on success or NULL on failure. | 
 | 167 |  */ | 
 | 168 | static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c) | 
 | 169 | { | 
 | 170 | 	return c->driver_data[i2o_scsi_driver.context]; | 
 | 171 | }; | 
 | 172 |  | 
 | 173 | /** | 
 | 174 |  *	i2o_scsi_remove - Remove I2O device from SCSI core | 
 | 175 |  *	@dev: device which should be removed | 
 | 176 |  * | 
 | 177 |  *	Removes the I2O device from the SCSI core again. | 
 | 178 |  * | 
 | 179 |  *	Returns 0 on success. | 
 | 180 |  */ | 
 | 181 | static int i2o_scsi_remove(struct device *dev) | 
 | 182 | { | 
 | 183 | 	struct i2o_device *i2o_dev = to_i2o_device(dev); | 
 | 184 | 	struct i2o_controller *c = i2o_dev->iop; | 
 | 185 | 	struct i2o_scsi_host *i2o_shost; | 
 | 186 | 	struct scsi_device *scsi_dev; | 
 | 187 |  | 
| Markus Lidel | f88e119 | 2005-06-23 22:02:14 -0700 | [diff] [blame] | 188 | 	osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid); | 
 | 189 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 | 	i2o_shost = i2o_scsi_get_host(c); | 
 | 191 |  | 
 | 192 | 	shost_for_each_device(scsi_dev, i2o_shost->scsi_host) | 
 | 193 | 	    if (scsi_dev->hostdata == i2o_dev) { | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 194 | 		sysfs_remove_link(&i2o_dev->device.kobj, "scsi"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | 		scsi_remove_device(scsi_dev); | 
 | 196 | 		scsi_device_put(scsi_dev); | 
 | 197 | 		break; | 
 | 198 | 	} | 
 | 199 |  | 
 | 200 | 	return 0; | 
 | 201 | }; | 
 | 202 |  | 
 | 203 | /** | 
 | 204 |  *	i2o_scsi_probe - verify if dev is a I2O SCSI device and install it | 
 | 205 |  *	@dev: device to verify if it is a I2O SCSI device | 
 | 206 |  * | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 207 |  *	Retrieve channel, id and lun for I2O device. If everything goes well | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 |  *	register the I2O device as SCSI device on the I2O SCSI controller. | 
 | 209 |  * | 
 | 210 |  *	Returns 0 on success or negative error code on failure. | 
 | 211 |  */ | 
 | 212 | static int i2o_scsi_probe(struct device *dev) | 
 | 213 | { | 
 | 214 | 	struct i2o_device *i2o_dev = to_i2o_device(dev); | 
 | 215 | 	struct i2o_controller *c = i2o_dev->iop; | 
 | 216 | 	struct i2o_scsi_host *i2o_shost; | 
 | 217 | 	struct Scsi_Host *scsi_host; | 
 | 218 | 	struct i2o_device *parent; | 
 | 219 | 	struct scsi_device *scsi_dev; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 220 | 	u32 id = -1; | 
 | 221 | 	u64 lun = -1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 222 | 	int channel = -1; | 
| Jeff Garzik | 3889b26 | 2006-12-06 20:35:31 -0800 | [diff] [blame] | 223 | 	int i, rc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 224 |  | 
 | 225 | 	i2o_shost = i2o_scsi_get_host(c); | 
 | 226 | 	if (!i2o_shost) | 
 | 227 | 		return -EFAULT; | 
 | 228 |  | 
 | 229 | 	scsi_host = i2o_shost->scsi_host; | 
 | 230 |  | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 231 | 	switch (i2o_dev->lct_data.class_id) { | 
 | 232 | 	case I2O_CLASS_RANDOM_BLOCK_STORAGE: | 
 | 233 | 	case I2O_CLASS_EXECUTIVE: | 
 | 234 | #ifdef CONFIG_I2O_EXT_ADAPTEC | 
 | 235 | 		if (c->adaptec) { | 
 | 236 | 			u8 type; | 
 | 237 | 			struct i2o_device *d = i2o_shost->channel[0]; | 
 | 238 |  | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 239 | 			if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1) | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 240 | 			    && (type == 0x01))	/* SCSI bus */ | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 241 | 				if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) { | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 242 | 					channel = 0; | 
 | 243 | 					if (i2o_dev->lct_data.class_id == | 
 | 244 | 					    I2O_CLASS_RANDOM_BLOCK_STORAGE) | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 245 | 						lun = | 
 | 246 | 						    cpu_to_le64(i2o_shost-> | 
 | 247 | 								lun++); | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 248 | 					else | 
 | 249 | 						lun = 0; | 
 | 250 | 				} | 
 | 251 | 		} | 
 | 252 | #endif | 
 | 253 | 		break; | 
 | 254 |  | 
 | 255 | 	case I2O_CLASS_SCSI_PERIPHERAL: | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 256 | 		if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4)) | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 257 | 			return -EFAULT; | 
 | 258 |  | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 259 | 		if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8)) | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 260 | 			return -EFAULT; | 
 | 261 |  | 
 | 262 | 		parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid); | 
 | 263 | 		if (!parent) { | 
 | 264 | 			osm_warn("can not find parent of device %03x\n", | 
 | 265 | 				 i2o_dev->lct_data.tid); | 
 | 266 | 			return -EFAULT; | 
 | 267 | 		} | 
 | 268 |  | 
 | 269 | 		for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++) | 
 | 270 | 			if (i2o_shost->channel[i] == parent) | 
 | 271 | 				channel = i; | 
 | 272 | 		break; | 
 | 273 |  | 
 | 274 | 	default: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 275 | 		return -EFAULT; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 276 | 	} | 
 | 277 |  | 
 | 278 | 	if (channel == -1) { | 
 | 279 | 		osm_warn("can not find channel of device %03x\n", | 
 | 280 | 			 i2o_dev->lct_data.tid); | 
 | 281 | 		return -EFAULT; | 
 | 282 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 283 |  | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 284 | 	if (le32_to_cpu(id) >= scsi_host->max_id) { | 
 | 285 | 		osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)", | 
 | 286 | 			 le32_to_cpu(id), scsi_host->max_id); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 287 | 		return -EFAULT; | 
 | 288 | 	} | 
 | 289 |  | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 290 | 	if (le64_to_cpu(lun) >= scsi_host->max_lun) { | 
 | 291 | 		osm_warn("SCSI device lun (%lu) >= max_lun of I2O host (%d)", | 
 | 292 | 			 (long unsigned int)le64_to_cpu(lun), | 
 | 293 | 			 scsi_host->max_lun); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 294 | 		return -EFAULT; | 
 | 295 | 	} | 
 | 296 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 | 	scsi_dev = | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 298 | 	    __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id), | 
 | 299 | 			      le64_to_cpu(lun), i2o_dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 300 |  | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 301 | 	if (IS_ERR(scsi_dev)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 | 		osm_warn("can not add SCSI device %03x\n", | 
 | 303 | 			 i2o_dev->lct_data.tid); | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 304 | 		return PTR_ERR(scsi_dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 305 | 	} | 
 | 306 |  | 
| Jeff Garzik | 3889b26 | 2006-12-06 20:35:31 -0800 | [diff] [blame] | 307 | 	rc = sysfs_create_link(&i2o_dev->device.kobj, | 
 | 308 | 			       &scsi_dev->sdev_gendev.kobj, "scsi"); | 
 | 309 | 	if (rc) | 
 | 310 | 		goto err; | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 311 |  | 
| Markus Lidel | dcceafe | 2006-01-06 00:19:32 -0800 | [diff] [blame] | 312 | 	osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %ld\n", | 
| Markus Lidel | 793fd15 | 2006-01-06 00:19:30 -0800 | [diff] [blame] | 313 | 		 i2o_dev->lct_data.tid, channel, le32_to_cpu(id), | 
| Markus Lidel | dcceafe | 2006-01-06 00:19:32 -0800 | [diff] [blame] | 314 | 		 (long unsigned int)le64_to_cpu(lun)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 315 |  | 
 | 316 | 	return 0; | 
| Jeff Garzik | 3889b26 | 2006-12-06 20:35:31 -0800 | [diff] [blame] | 317 |  | 
 | 318 | err: | 
 | 319 | 	scsi_remove_device(scsi_dev); | 
 | 320 | 	return rc; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 321 | }; | 
 | 322 |  | 
 | 323 | static const char *i2o_scsi_info(struct Scsi_Host *SChost) | 
 | 324 | { | 
 | 325 | 	struct i2o_scsi_host *hostdata; | 
 | 326 | 	hostdata = (struct i2o_scsi_host *)SChost->hostdata; | 
 | 327 | 	return hostdata->iop->name; | 
 | 328 | } | 
 | 329 |  | 
 | 330 | /** | 
 | 331 |  *	i2o_scsi_reply - SCSI OSM message reply handler | 
 | 332 |  *	@c: controller issuing the reply | 
 | 333 |  *	@m: message id for flushing | 
 | 334 |  *	@msg: the message from the controller | 
 | 335 |  * | 
 | 336 |  *	Process reply messages (interrupts in normal scsi controller think). | 
 | 337 |  *	We can get a variety of messages to process. The normal path is | 
 | 338 |  *	scsi command completions. We must also deal with IOP failures, | 
 | 339 |  *	the reply to a bus reset and the reply to a LUN query. | 
 | 340 |  * | 
 | 341 |  *	Returns 0 on success and if the reply should not be flushed or > 0 | 
 | 342 |  *	on success and if the reply should be flushed. Returns negative error | 
 | 343 |  *	code on failure and if the reply should be flushed. | 
 | 344 |  */ | 
 | 345 | static int i2o_scsi_reply(struct i2o_controller *c, u32 m, | 
 | 346 | 			  struct i2o_message *msg) | 
 | 347 | { | 
 | 348 | 	struct scsi_cmnd *cmd; | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 349 | 	u32 error; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 | 	struct device *dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 351 |  | 
 | 352 | 	cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt)); | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 353 | 	if (unlikely(!cmd)) { | 
 | 354 | 		osm_err("NULL reply received!\n"); | 
 | 355 | 		return -1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 356 | 	} | 
 | 357 |  | 
 | 358 | 	/* | 
 | 359 | 	 *      Low byte is device status, next is adapter status, | 
 | 360 | 	 *      (then one byte reserved), then request status. | 
 | 361 | 	 */ | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 362 | 	error = le32_to_cpu(msg->body[0]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 363 |  | 
| Christoph Hellwig | 5cd049a | 2011-04-04 09:42:14 -0400 | [diff] [blame] | 364 | 	osm_debug("Completed %0x%p\n", cmd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 365 |  | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 366 | 	cmd->result = error & 0xff; | 
 | 367 | 	/* | 
 | 368 | 	 * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let | 
 | 369 | 	 * the SCSI layer handle the error | 
 | 370 | 	 */ | 
 | 371 | 	if (cmd->result) | 
 | 372 | 		memcpy(cmd->sense_buffer, &msg->body[3], | 
| FUJITA Tomonori | b80ca4f | 2008-01-13 15:46:13 +0900 | [diff] [blame] | 373 | 		       min(SCSI_SENSE_BUFFERSIZE, 40)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 374 |  | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 375 | 	/* only output error code if AdapterStatus is not HBA_SUCCESS */ | 
 | 376 | 	if ((error >> 8) & 0xff) | 
 | 377 | 		osm_err("SCSI error %08x\n", error); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 378 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 379 | 	dev = &c->pdev->dev; | 
| FUJITA Tomonori | 0ea7154 | 2007-06-14 00:41:06 +0900 | [diff] [blame] | 380 |  | 
 | 381 | 	scsi_dma_unmap(cmd); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 382 |  | 
| Markus Lidel | f88e119 | 2005-06-23 22:02:14 -0700 | [diff] [blame] | 383 | 	cmd->scsi_done(cmd); | 
 | 384 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 385 | 	return 1; | 
 | 386 | }; | 
 | 387 |  | 
 | 388 | /** | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 389 |  *	i2o_scsi_notify_device_add - Retrieve notifications of added devices | 
 | 390 |  *	@i2o_dev: the I2O device which was added | 
 | 391 |  * | 
 | 392 |  *	If a I2O device is added we catch the notification, because I2O classes | 
| Frederik Schwarzer | 025dfda | 2008-10-16 19:02:37 +0200 | [diff] [blame] | 393 |  *	other than SCSI peripheral will not be received through | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 394 |  *	i2o_scsi_probe(). | 
 | 395 |  */ | 
 | 396 | static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev) | 
 | 397 | { | 
 | 398 | 	switch (i2o_dev->lct_data.class_id) { | 
 | 399 | 	case I2O_CLASS_EXECUTIVE: | 
 | 400 | 	case I2O_CLASS_RANDOM_BLOCK_STORAGE: | 
 | 401 | 		i2o_scsi_probe(&i2o_dev->device); | 
 | 402 | 		break; | 
 | 403 |  | 
 | 404 | 	default: | 
 | 405 | 		break; | 
 | 406 | 	} | 
 | 407 | }; | 
 | 408 |  | 
 | 409 | /** | 
| Randy Dunlap | d9489fb | 2006-12-06 20:38:43 -0800 | [diff] [blame] | 410 |  *	i2o_scsi_notify_device_remove - Retrieve notifications of removed devices | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 411 |  *	@i2o_dev: the I2O device which was removed | 
 | 412 |  * | 
 | 413 |  *	If a I2O device is removed, we catch the notification to remove the | 
 | 414 |  *	corresponding SCSI device. | 
 | 415 |  */ | 
 | 416 | static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev) | 
 | 417 | { | 
 | 418 | 	switch (i2o_dev->lct_data.class_id) { | 
 | 419 | 	case I2O_CLASS_EXECUTIVE: | 
 | 420 | 	case I2O_CLASS_RANDOM_BLOCK_STORAGE: | 
 | 421 | 		i2o_scsi_remove(&i2o_dev->device); | 
 | 422 | 		break; | 
 | 423 |  | 
 | 424 | 	default: | 
 | 425 | 		break; | 
 | 426 | 	} | 
 | 427 | }; | 
 | 428 |  | 
 | 429 | /** | 
| Randy Dunlap | d9489fb | 2006-12-06 20:38:43 -0800 | [diff] [blame] | 430 |  *	i2o_scsi_notify_controller_add - Retrieve notifications of added controllers | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 431 |  *	@c: the controller which was added | 
 | 432 |  * | 
 | 433 |  *	If a I2O controller is added, we catch the notification to add a | 
 | 434 |  *	corresponding Scsi_Host. | 
 | 435 |  */ | 
 | 436 | static void i2o_scsi_notify_controller_add(struct i2o_controller *c) | 
 | 437 | { | 
 | 438 | 	struct i2o_scsi_host *i2o_shost; | 
 | 439 | 	int rc; | 
 | 440 |  | 
 | 441 | 	i2o_shost = i2o_scsi_host_alloc(c); | 
 | 442 | 	if (IS_ERR(i2o_shost)) { | 
 | 443 | 		osm_err("Could not initialize SCSI host\n"); | 
 | 444 | 		return; | 
 | 445 | 	} | 
 | 446 |  | 
 | 447 | 	rc = scsi_add_host(i2o_shost->scsi_host, &c->device); | 
 | 448 | 	if (rc) { | 
 | 449 | 		osm_err("Could not add SCSI host\n"); | 
 | 450 | 		scsi_host_put(i2o_shost->scsi_host); | 
 | 451 | 		return; | 
 | 452 | 	} | 
 | 453 |  | 
 | 454 | 	c->driver_data[i2o_scsi_driver.context] = i2o_shost; | 
 | 455 |  | 
 | 456 | 	osm_debug("new I2O SCSI host added\n"); | 
 | 457 | }; | 
 | 458 |  | 
 | 459 | /** | 
| Randy Dunlap | d9489fb | 2006-12-06 20:38:43 -0800 | [diff] [blame] | 460 |  *	i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 461 |  *	@c: the controller which was removed | 
 | 462 |  * | 
 | 463 |  *	If a I2O controller is removed, we catch the notification to remove the | 
 | 464 |  *	corresponding Scsi_Host. | 
 | 465 |  */ | 
 | 466 | static void i2o_scsi_notify_controller_remove(struct i2o_controller *c) | 
 | 467 | { | 
 | 468 | 	struct i2o_scsi_host *i2o_shost; | 
 | 469 | 	i2o_shost = i2o_scsi_get_host(c); | 
 | 470 | 	if (!i2o_shost) | 
 | 471 | 		return; | 
 | 472 |  | 
 | 473 | 	c->driver_data[i2o_scsi_driver.context] = NULL; | 
 | 474 |  | 
 | 475 | 	scsi_remove_host(i2o_shost->scsi_host); | 
 | 476 | 	scsi_host_put(i2o_shost->scsi_host); | 
| Markus Lidel | f88e119 | 2005-06-23 22:02:14 -0700 | [diff] [blame] | 477 | 	osm_debug("I2O SCSI host removed\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 478 | }; | 
 | 479 |  | 
 | 480 | /* SCSI OSM driver struct */ | 
 | 481 | static struct i2o_driver i2o_scsi_driver = { | 
 | 482 | 	.name = OSM_NAME, | 
 | 483 | 	.reply = i2o_scsi_reply, | 
 | 484 | 	.classes = i2o_scsi_class_id, | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 485 | 	.notify_device_add = i2o_scsi_notify_device_add, | 
 | 486 | 	.notify_device_remove = i2o_scsi_notify_device_remove, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 487 | 	.notify_controller_add = i2o_scsi_notify_controller_add, | 
 | 488 | 	.notify_controller_remove = i2o_scsi_notify_controller_remove, | 
 | 489 | 	.driver = { | 
 | 490 | 		   .probe = i2o_scsi_probe, | 
 | 491 | 		   .remove = i2o_scsi_remove, | 
 | 492 | 		   }, | 
 | 493 | }; | 
 | 494 |  | 
 | 495 | /** | 
 | 496 |  *	i2o_scsi_queuecommand - queue a SCSI command | 
 | 497 |  *	@SCpnt: scsi command pointer | 
 | 498 |  *	@done: callback for completion | 
 | 499 |  * | 
 | 500 |  *	Issue a scsi command asynchronously. Return 0 on success or 1 if | 
 | 501 |  *	we hit an error (normally message queue congestion). The only | 
 | 502 |  *	minor complication here is that I2O deals with the device addressing | 
 | 503 |  *	so we have to map the bus/dev/lun back to an I2O handle as well | 
 | 504 |  *	as faking absent devices ourself. | 
 | 505 |  * | 
 | 506 |  *	Locks: takes the controller lock on error path only | 
 | 507 |  */ | 
 | 508 |  | 
| Jeff Garzik | f281233 | 2010-11-16 02:10:29 -0500 | [diff] [blame] | 509 | static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 510 | 				 void (*done) (struct scsi_cmnd *)) | 
 | 511 | { | 
 | 512 | 	struct i2o_controller *c; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 513 | 	struct i2o_device *i2o_dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 514 | 	int tid; | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 515 | 	struct i2o_message *msg; | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 516 | 	/* | 
 | 517 | 	 * ENABLE_DISCONNECT | 
 | 518 | 	 * SIMPLE_TAG | 
 | 519 | 	 * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME | 
 | 520 | 	 */ | 
 | 521 | 	u32 scsi_flags = 0x20a00000; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 522 | 	u32 sgl_offset; | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 523 | 	u32 *mptr; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 524 | 	u32 cmd = I2O_CMD_SCSI_EXEC << 24; | 
 | 525 | 	int rc = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 526 |  | 
 | 527 | 	/* | 
 | 528 | 	 *      Do the incoming paperwork | 
 | 529 | 	 */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 530 | 	i2o_dev = SCpnt->device->hostdata; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 531 |  | 
 | 532 | 	SCpnt->scsi_done = done; | 
 | 533 |  | 
 | 534 | 	if (unlikely(!i2o_dev)) { | 
 | 535 | 		osm_warn("no I2O device in request\n"); | 
 | 536 | 		SCpnt->result = DID_NO_CONNECT << 16; | 
 | 537 | 		done(SCpnt); | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 538 | 		goto exit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 539 | 	} | 
| Julia Lawall | d236700 | 2010-08-10 18:01:14 -0700 | [diff] [blame] | 540 | 	c = i2o_dev->iop; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 541 | 	tid = i2o_dev->lct_data.tid; | 
 | 542 |  | 
 | 543 | 	osm_debug("qcmd: Tid = %03x\n", tid); | 
 | 544 | 	osm_debug("Real scsi messages.\n"); | 
 | 545 |  | 
 | 546 | 	/* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 547 | 	 *      Put together a scsi execscb message | 
 | 548 | 	 */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 549 | 	switch (SCpnt->sc_data_direction) { | 
 | 550 | 	case PCI_DMA_NONE: | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 551 | 		/* DATA NO XFER */ | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 552 | 		sgl_offset = SGL_OFFSET_0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 553 | 		break; | 
 | 554 |  | 
 | 555 | 	case PCI_DMA_TODEVICE: | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 556 | 		/* DATA OUT (iop-->dev) */ | 
 | 557 | 		scsi_flags |= 0x80000000; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 558 | 		sgl_offset = SGL_OFFSET_10; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 559 | 		break; | 
 | 560 |  | 
 | 561 | 	case PCI_DMA_FROMDEVICE: | 
| Markus Lidel | f10378f | 2005-06-23 22:02:16 -0700 | [diff] [blame] | 562 | 		/* DATA IN  (iop<--dev) */ | 
 | 563 | 		scsi_flags |= 0x40000000; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 564 | 		sgl_offset = SGL_OFFSET_10; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 565 | 		break; | 
 | 566 |  | 
 | 567 | 	default: | 
 | 568 | 		/* Unknown - kill the command */ | 
 | 569 | 		SCpnt->result = DID_NO_CONNECT << 16; | 
 | 570 | 		done(SCpnt); | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 571 | 		goto exit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 572 | 	} | 
 | 573 |  | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 574 | 	/* | 
 | 575 | 	 *      Obtain an I2O message. If there are none free then | 
 | 576 | 	 *      throw it back to the scsi layer | 
 | 577 | 	 */ | 
 | 578 |  | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 579 | 	msg = i2o_msg_get(c); | 
 | 580 | 	if (IS_ERR(msg)) { | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 581 | 		rc = SCSI_MLQUEUE_HOST_BUSY; | 
 | 582 | 		goto exit; | 
 | 583 | 	} | 
 | 584 |  | 
 | 585 | 	mptr = &msg->body[0]; | 
 | 586 |  | 
| Christoph Hellwig | beb4048 | 2006-06-10 18:01:03 +0200 | [diff] [blame] | 587 | #if 0 /* this code can't work */ | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 588 | #ifdef CONFIG_I2O_EXT_ADAPTEC | 
 | 589 | 	if (c->adaptec) { | 
 | 590 | 		u32 adpt_flags = 0; | 
 | 591 |  | 
 | 592 | 		if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) { | 
 | 593 | 			i2o_sg_io_hdr_t __user *usr_ptr = | 
 | 594 | 			    ((Sg_request *) (SCpnt->sc_request-> | 
 | 595 | 					     upper_private_data))->header. | 
 | 596 | 			    usr_ptr; | 
 | 597 |  | 
 | 598 | 			if (usr_ptr) | 
 | 599 | 				get_user(adpt_flags, &usr_ptr->flags); | 
 | 600 | 		} | 
 | 601 |  | 
 | 602 | 		switch (i2o_dev->lct_data.class_id) { | 
 | 603 | 		case I2O_CLASS_EXECUTIVE: | 
 | 604 | 		case I2O_CLASS_RANDOM_BLOCK_STORAGE: | 
 | 605 | 			/* interpret flag has to be set for executive */ | 
 | 606 | 			adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET; | 
 | 607 | 			break; | 
 | 608 |  | 
 | 609 | 		default: | 
 | 610 | 			break; | 
 | 611 | 		} | 
 | 612 |  | 
 | 613 | 		/* | 
 | 614 | 		 * for Adaptec controllers we use the PRIVATE command, because | 
 | 615 | 		 * the normal SCSI EXEC doesn't support all SCSI commands on | 
 | 616 | 		 * all controllers (for example READ CAPACITY). | 
 | 617 | 		 */ | 
 | 618 | 		if (sgl_offset == SGL_OFFSET_10) | 
 | 619 | 			sgl_offset = SGL_OFFSET_12; | 
 | 620 | 		cmd = I2O_CMD_PRIVATE << 24; | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 621 | 		*mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC); | 
 | 622 | 		*mptr++ = cpu_to_le32(adpt_flags | tid); | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 623 | 	} | 
 | 624 | #endif | 
| Christoph Hellwig | beb4048 | 2006-06-10 18:01:03 +0200 | [diff] [blame] | 625 | #endif | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 626 |  | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 627 | 	msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); | 
 | 628 | 	msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 629 |  | 
 | 630 | 	/* We want the SCSI control block back */ | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 631 | 	msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 632 |  | 
 | 633 | 	/* LSI_920_PCI_QUIRK | 
 | 634 | 	 * | 
 | 635 | 	 *      Intermittant observations of msg frame word data corruption | 
 | 636 | 	 *      observed on msg[4] after: | 
 | 637 | 	 *        WRITE, READ-MODIFY-WRITE | 
 | 638 | 	 *      operations.  19990606 -sralston | 
 | 639 | 	 * | 
 | 640 | 	 *      (Hence we build this word via tag. Its good practice anyway | 
 | 641 | 	 *       we don't want fetches over PCI needlessly) | 
 | 642 | 	 */ | 
 | 643 |  | 
 | 644 | 	/* Attach tags to the devices */ | 
| Markus Lidel | 9e87545 | 2005-06-23 22:02:21 -0700 | [diff] [blame] | 645 | 	/* FIXME: implement | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 646 | 	   if(SCpnt->device->tagged_supported) { | 
 | 647 | 	   if(SCpnt->tag == HEAD_OF_QUEUE_TAG) | 
 | 648 | 	   scsi_flags |= 0x01000000; | 
 | 649 | 	   else if(SCpnt->tag == ORDERED_QUEUE_TAG) | 
 | 650 | 	   scsi_flags |= 0x01800000; | 
 | 651 | 	   } | 
 | 652 | 	 */ | 
 | 653 |  | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 654 | 	*mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 655 |  | 
 | 656 | 	/* Write SCSI command into the message - always 16 byte block */ | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 657 | 	memcpy(mptr, SCpnt->cmnd, 16); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 658 | 	mptr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 659 |  | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 660 | 	if (sgl_offset != SGL_OFFSET_0) { | 
 | 661 | 		/* write size of data addressed by SGL */ | 
| FUJITA Tomonori | 0ea7154 | 2007-06-14 00:41:06 +0900 | [diff] [blame] | 662 | 		*mptr++ = cpu_to_le32(scsi_bufflen(SCpnt)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 663 |  | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 664 | 		/* Now fill in the SGList and command */ | 
| FUJITA Tomonori | 0ea7154 | 2007-06-14 00:41:06 +0900 | [diff] [blame] | 665 |  | 
 | 666 | 		if (scsi_sg_count(SCpnt)) { | 
 | 667 | 			if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt), | 
 | 668 | 					    scsi_sg_count(SCpnt), | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 669 | 					    SCpnt->sc_data_direction, &mptr)) | 
 | 670 | 				goto nomem; | 
| Markus Lidel | f88e119 | 2005-06-23 22:02:14 -0700 | [diff] [blame] | 671 | 		} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 672 | 	} | 
 | 673 |  | 
 | 674 | 	/* Stick the headers on */ | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 675 | 	msg->u.head[0] = | 
 | 676 | 	    cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 677 |  | 
 | 678 | 	/* Queue the message */ | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 679 | 	i2o_msg_post(c, msg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 680 |  | 
| Christoph Hellwig | 5cd049a | 2011-04-04 09:42:14 -0400 | [diff] [blame] | 681 | 	osm_debug("Issued %0x%p\n", SCpnt); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 682 |  | 
 | 683 | 	return 0; | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 684 |  | 
 | 685 |       nomem: | 
 | 686 | 	rc = -ENOMEM; | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 687 | 	i2o_msg_nop(c, msg); | 
| Markus Lidel | b2aaee3 | 2005-06-23 22:02:19 -0700 | [diff] [blame] | 688 |  | 
 | 689 |       exit: | 
 | 690 | 	return rc; | 
| Jeff Garzik | f281233 | 2010-11-16 02:10:29 -0500 | [diff] [blame] | 691 | } | 
 | 692 |  | 
 | 693 | static DEF_SCSI_QCMD(i2o_scsi_queuecommand) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 694 |  | 
 | 695 | /** | 
 | 696 |  *	i2o_scsi_abort - abort a running command | 
 | 697 |  *	@SCpnt: command to abort | 
 | 698 |  * | 
 | 699 |  *	Ask the I2O controller to abort a command. This is an asynchrnous | 
 | 700 |  *	process and our callback handler will see the command complete with an | 
 | 701 |  *	aborted message if it succeeds. | 
 | 702 |  * | 
 | 703 |  *	Returns 0 if the command is successfully aborted or negative error code | 
 | 704 |  *	on failure. | 
 | 705 |  */ | 
 | 706 | static int i2o_scsi_abort(struct scsi_cmnd *SCpnt) | 
 | 707 | { | 
 | 708 | 	struct i2o_device *i2o_dev; | 
 | 709 | 	struct i2o_controller *c; | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 710 | 	struct i2o_message *msg; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 711 | 	int tid; | 
 | 712 | 	int status = FAILED; | 
 | 713 |  | 
 | 714 | 	osm_warn("Aborting command block.\n"); | 
 | 715 |  | 
 | 716 | 	i2o_dev = SCpnt->device->hostdata; | 
 | 717 | 	c = i2o_dev->iop; | 
 | 718 | 	tid = i2o_dev->lct_data.tid; | 
 | 719 |  | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 720 | 	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); | 
 | 721 | 	if (IS_ERR(msg)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 722 | 		return SCSI_MLQUEUE_HOST_BUSY; | 
 | 723 |  | 
| Markus Lidel | a1a5ea7 | 2006-01-06 00:19:29 -0800 | [diff] [blame] | 724 | 	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0); | 
 | 725 | 	msg->u.head[1] = | 
 | 726 | 	    cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid); | 
 | 727 | 	msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 728 |  | 
| Markus Lidel | e22bec2 | 2006-02-04 23:27:39 -0800 | [diff] [blame] | 729 | 	if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 730 | 		status = SUCCESS; | 
 | 731 |  | 
 | 732 | 	return status; | 
 | 733 | } | 
 | 734 |  | 
 | 735 | /** | 
 | 736 |  *	i2o_scsi_bios_param	-	Invent disk geometry | 
 | 737 |  *	@sdev: scsi device | 
 | 738 |  *	@dev: block layer device | 
 | 739 |  *	@capacity: size in sectors | 
 | 740 |  *	@ip: geometry array | 
 | 741 |  * | 
| Randy Dunlap | d9489fb | 2006-12-06 20:38:43 -0800 | [diff] [blame] | 742 |  *	This is anyone's guess quite frankly. We use the same rules everyone | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 743 |  *	else appears to and hope. It seems to work. | 
 | 744 |  */ | 
 | 745 |  | 
 | 746 | static int i2o_scsi_bios_param(struct scsi_device *sdev, | 
 | 747 | 			       struct block_device *dev, sector_t capacity, | 
 | 748 | 			       int *ip) | 
 | 749 | { | 
 | 750 | 	int size; | 
 | 751 |  | 
 | 752 | 	size = capacity; | 
 | 753 | 	ip[0] = 64;		/* heads                        */ | 
 | 754 | 	ip[1] = 32;		/* sectors                      */ | 
 | 755 | 	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */ | 
 | 756 | 		ip[0] = 255;	/* heads                        */ | 
 | 757 | 		ip[1] = 63;	/* sectors                      */ | 
 | 758 | 		ip[2] = size / (255 * 63);	/* cylinders                    */ | 
 | 759 | 	} | 
 | 760 | 	return 0; | 
 | 761 | } | 
 | 762 |  | 
 | 763 | static struct scsi_host_template i2o_scsi_host_template = { | 
 | 764 | 	.proc_name = OSM_NAME, | 
 | 765 | 	.name = OSM_DESCRIPTION, | 
 | 766 | 	.info = i2o_scsi_info, | 
 | 767 | 	.queuecommand = i2o_scsi_queuecommand, | 
 | 768 | 	.eh_abort_handler = i2o_scsi_abort, | 
 | 769 | 	.bios_param = i2o_scsi_bios_param, | 
 | 770 | 	.can_queue = I2O_SCSI_CAN_QUEUE, | 
 | 771 | 	.sg_tablesize = 8, | 
 | 772 | 	.cmd_per_lun = 6, | 
 | 773 | 	.use_clustering = ENABLE_CLUSTERING, | 
 | 774 | }; | 
 | 775 |  | 
 | 776 | /** | 
 | 777 |  *	i2o_scsi_init - SCSI OSM initialization function | 
 | 778 |  * | 
 | 779 |  *	Register SCSI OSM into I2O core. | 
 | 780 |  * | 
 | 781 |  *	Returns 0 on success or negative error code on failure. | 
 | 782 |  */ | 
 | 783 | static int __init i2o_scsi_init(void) | 
 | 784 | { | 
 | 785 | 	int rc; | 
 | 786 |  | 
 | 787 | 	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); | 
 | 788 |  | 
 | 789 | 	/* Register SCSI OSM into I2O core */ | 
 | 790 | 	rc = i2o_driver_register(&i2o_scsi_driver); | 
 | 791 | 	if (rc) { | 
 | 792 | 		osm_err("Could not register SCSI driver\n"); | 
 | 793 | 		return rc; | 
 | 794 | 	} | 
 | 795 |  | 
 | 796 | 	return 0; | 
 | 797 | }; | 
 | 798 |  | 
 | 799 | /** | 
 | 800 |  *	i2o_scsi_exit - SCSI OSM exit function | 
 | 801 |  * | 
 | 802 |  *	Unregisters SCSI OSM from I2O core. | 
 | 803 |  */ | 
 | 804 | static void __exit i2o_scsi_exit(void) | 
 | 805 | { | 
 | 806 | 	/* Unregister I2O SCSI OSM from I2O core */ | 
 | 807 | 	i2o_driver_unregister(&i2o_scsi_driver); | 
 | 808 | }; | 
 | 809 |  | 
 | 810 | MODULE_AUTHOR("Red Hat Software"); | 
 | 811 | MODULE_LICENSE("GPL"); | 
 | 812 | MODULE_DESCRIPTION(OSM_DESCRIPTION); | 
 | 813 | MODULE_VERSION(OSM_VERSION); | 
 | 814 |  | 
 | 815 | module_init(i2o_scsi_init); | 
 | 816 | module_exit(i2o_scsi_exit); |