diff options
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 9 | ||||
-rw-r--r-- | MAINTAINERS | 5 | ||||
-rw-r--r-- | drivers/ide/Kconfig | 17 | ||||
-rw-r--r-- | drivers/scsi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/scsi/Makefile | 1 | ||||
-rw-r--r-- | drivers/scsi/ide-scsi.c | 840 |
6 files changed, 4 insertions, 876 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index dc7c681e532c..df18d87c4837 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -310,15 +310,6 @@ Who: Krzysztof Piotr Oledzki <ole@ans.pl> | |||
310 | 310 | ||
311 | --------------------------- | 311 | --------------------------- |
312 | 312 | ||
313 | What: ide-scsi (BLK_DEV_IDESCSI) | ||
314 | When: 2.6.29 | ||
315 | Why: The 2.6 kernel supports direct writing to ide CD drives, which | ||
316 | eliminates the need for ide-scsi. The new method is more | ||
317 | efficient in every way. | ||
318 | Who: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | ||
319 | |||
320 | --------------------------- | ||
321 | |||
322 | What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client() | 313 | What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client() |
323 | When: 2.6.29 (ideally) or 2.6.30 (more likely) | 314 | When: 2.6.29 (ideally) or 2.6.30 (more likely) |
324 | Why: Deprecated by the new (standard) device driver binding model. Use | 315 | Why: Deprecated by the new (standard) device driver binding model. Use |
diff --git a/MAINTAINERS b/MAINTAINERS index ceb32ee51f9d..144766c0dba3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2146,11 +2146,6 @@ M: Gadi Oxman <gadio@netvision.net.il> | |||
2146 | L: linux-kernel@vger.kernel.org | 2146 | L: linux-kernel@vger.kernel.org |
2147 | S: Maintained | 2147 | S: Maintained |
2148 | 2148 | ||
2149 | IDE-SCSI DRIVER | ||
2150 | L: linux-ide@vger.kernel.org | ||
2151 | L: linux-scsi@vger.kernel.org | ||
2152 | S: Orphan | ||
2153 | |||
2154 | IDLE-I7300 | 2149 | IDLE-I7300 |
2155 | P: Andy Henroid | 2150 | P: Andy Henroid |
2156 | M: andrew.d.henroid@intel.com | 2151 | M: andrew.d.henroid@intel.com |
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index c9f21e3d4ead..937945e471df 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig | |||
@@ -185,23 +185,6 @@ config BLK_DEV_IDETAPE | |||
185 | To compile this driver as a module, choose M here: the | 185 | To compile this driver as a module, choose M here: the |
186 | module will be called ide-tape. | 186 | module will be called ide-tape. |
187 | 187 | ||
188 | config BLK_DEV_IDESCSI | ||
189 | tristate "SCSI emulation support (DEPRECATED)" | ||
190 | depends on SCSI | ||
191 | select IDE_ATAPI | ||
192 | ---help--- | ||
193 | WARNING: ide-scsi is no longer needed for cd writing applications! | ||
194 | The 2.6 kernel supports direct writing to ide-cd, which eliminates | ||
195 | the need for ide-scsi + the entire scsi stack just for writing a | ||
196 | cd. The new method is more efficient in every way. | ||
197 | |||
198 | This will provide SCSI host adapter emulation for IDE ATAPI devices, | ||
199 | and will allow you to use a SCSI device driver instead of a native | ||
200 | ATAPI driver. | ||
201 | |||
202 | If both this SCSI emulation and native ATAPI support are compiled | ||
203 | into the kernel, the native support will be used. | ||
204 | |||
205 | config BLK_DEV_IDEACPI | 188 | config BLK_DEV_IDEACPI |
206 | bool "IDE ACPI support" | 189 | bool "IDE ACPI support" |
207 | depends on ACPI | 190 | depends on ACPI |
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 152d4aa9354f..b7322976d2b7 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -21,7 +21,7 @@ config SCSI | |||
21 | You also need to say Y here if you have a device which speaks | 21 | You also need to say Y here if you have a device which speaks |
22 | the SCSI protocol. Examples of this include the parallel port | 22 | the SCSI protocol. Examples of this include the parallel port |
23 | version of the IOMEGA ZIP drive, USB storage devices, Fibre | 23 | version of the IOMEGA ZIP drive, USB storage devices, Fibre |
24 | Channel, FireWire storage and the IDE-SCSI emulation driver. | 24 | Channel, and FireWire storage. |
25 | 25 | ||
26 | To compile this driver as a module, choose M here and read | 26 | To compile this driver as a module, choose M here and read |
27 | <file:Documentation/scsi/scsi.txt>. | 27 | <file:Documentation/scsi/scsi.txt>. |
@@ -101,9 +101,9 @@ config CHR_DEV_OSST | |||
101 | ---help--- | 101 | ---help--- |
102 | The OnStream SC-x0 SCSI tape drives cannot be driven by the | 102 | The OnStream SC-x0 SCSI tape drives cannot be driven by the |
103 | standard st driver, but instead need this special osst driver and | 103 | standard st driver, but instead need this special osst driver and |
104 | use the /dev/osstX char device nodes (major 206). Via usb-storage | 104 | use the /dev/osstX char device nodes (major 206). Via usb-storage, |
105 | and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives | 105 | you may be able to drive the USB-x0 and DI-x0 drives as well. |
106 | as well. Note that there is also a second generation of OnStream | 106 | Note that there is also a second generation of OnStream |
107 | tape drives (ADR-x0) that supports the standard SCSI-2 commands for | 107 | tape drives (ADR-x0) that supports the standard SCSI-2 commands for |
108 | tapes (QIC-157) and can be driven by the standard driver st. | 108 | tapes (QIC-157) and can be driven by the standard driver st. |
109 | For more information, you may have a look at the SCSI-HOWTO | 109 | For more information, you may have a look at the SCSI-HOWTO |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 1410697257cb..7461eb09a031 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -105,7 +105,6 @@ obj-$(CONFIG_SCSI_GDTH) += gdth.o | |||
105 | obj-$(CONFIG_SCSI_INITIO) += initio.o | 105 | obj-$(CONFIG_SCSI_INITIO) += initio.o |
106 | obj-$(CONFIG_SCSI_INIA100) += a100u2w.o | 106 | obj-$(CONFIG_SCSI_INIA100) += a100u2w.o |
107 | obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o | 107 | obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o |
108 | obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o | ||
109 | obj-$(CONFIG_SCSI_MESH) += mesh.o | 108 | obj-$(CONFIG_SCSI_MESH) += mesh.o |
110 | obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o | 109 | obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o |
111 | obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o | 110 | obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o |
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c deleted file mode 100644 index c24140aff8e7..000000000000 --- a/drivers/scsi/ide-scsi.c +++ /dev/null | |||
@@ -1,840 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il> | ||
3 | * Copyright (C) 2004-2005 Bartlomiej Zolnierkiewicz | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * Emulation of a SCSI host adapter for IDE ATAPI devices. | ||
8 | * | ||
9 | * With this driver, one can use the Linux SCSI drivers instead of the | ||
10 | * native IDE ATAPI drivers. | ||
11 | * | ||
12 | * Ver 0.1 Dec 3 96 Initial version. | ||
13 | * Ver 0.2 Jan 26 97 Fixed bug in cleanup_module() and added emulation | ||
14 | * of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks | ||
15 | * to Janos Farkas for pointing this out. | ||
16 | * Avoid using bitfields in structures for m68k. | ||
17 | * Added Scatter/Gather and DMA support. | ||
18 | * Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives. | ||
19 | * Use variable timeout for each command. | ||
20 | * Ver 0.5 Jan 2 98 Fix previous PD/CD support. | ||
21 | * Allow disabling of SCSI-6 to SCSI-10 transformation. | ||
22 | * Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer | ||
23 | * for access through /dev/sg. | ||
24 | * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. | ||
25 | * Ver 0.7 Dec 04 98 Ignore commands where lun != 0 to avoid multiple | ||
26 | * detection of devices with CONFIG_SCSI_MULTI_LUN | ||
27 | * Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7. | ||
28 | * Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM. | ||
29 | * Ver 0.91 Jun 10 02 Fix "off by one" error in transforms | ||
30 | * Ver 0.92 Dec 31 02 Implement new SCSI mid level API | ||
31 | */ | ||
32 | |||
33 | #define IDESCSI_VERSION "0.92" | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/types.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/mm.h> | ||
40 | #include <linux/ioport.h> | ||
41 | #include <linux/blkdev.h> | ||
42 | #include <linux/errno.h> | ||
43 | #include <linux/slab.h> | ||
44 | #include <linux/ide.h> | ||
45 | #include <linux/scatterlist.h> | ||
46 | #include <linux/delay.h> | ||
47 | #include <linux/mutex.h> | ||
48 | #include <linux/bitops.h> | ||
49 | |||
50 | #include <asm/io.h> | ||
51 | #include <asm/uaccess.h> | ||
52 | |||
53 | #include <scsi/scsi.h> | ||
54 | #include <scsi/scsi_cmnd.h> | ||
55 | #include <scsi/scsi_device.h> | ||
56 | #include <scsi/scsi_host.h> | ||
57 | #include <scsi/scsi_tcq.h> | ||
58 | #include <scsi/sg.h> | ||
59 | |||
60 | #define IDESCSI_DEBUG_LOG 0 | ||
61 | |||
62 | #if IDESCSI_DEBUG_LOG | ||
63 | #define debug_log(fmt, args...) \ | ||
64 | printk(KERN_INFO "ide-scsi: " fmt, ## args) | ||
65 | #else | ||
66 | #define debug_log(fmt, args...) do {} while (0) | ||
67 | #endif | ||
68 | |||
69 | /* | ||
70 | * SCSI command transformation layer | ||
71 | */ | ||
72 | #define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */ | ||
73 | |||
74 | /* | ||
75 | * Log flags | ||
76 | */ | ||
77 | #define IDESCSI_LOG_CMD 0 /* Log SCSI commands */ | ||
78 | |||
79 | typedef struct ide_scsi_obj { | ||
80 | ide_drive_t *drive; | ||
81 | ide_driver_t *driver; | ||
82 | struct gendisk *disk; | ||
83 | struct Scsi_Host *host; | ||
84 | |||
85 | unsigned long transform; /* SCSI cmd translation layer */ | ||
86 | unsigned long log; /* log flags */ | ||
87 | } idescsi_scsi_t; | ||
88 | |||
89 | static DEFINE_MUTEX(idescsi_ref_mutex); | ||
90 | /* Set by module param to skip cd */ | ||
91 | static int idescsi_nocd; | ||
92 | |||
93 | #define ide_scsi_g(disk) \ | ||
94 | container_of((disk)->private_data, struct ide_scsi_obj, driver) | ||
95 | |||
96 | static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk) | ||
97 | { | ||
98 | struct ide_scsi_obj *scsi = NULL; | ||
99 | |||
100 | mutex_lock(&idescsi_ref_mutex); | ||
101 | scsi = ide_scsi_g(disk); | ||
102 | if (scsi) { | ||
103 | if (ide_device_get(scsi->drive)) | ||
104 | scsi = NULL; | ||
105 | else | ||
106 | scsi_host_get(scsi->host); | ||
107 | } | ||
108 | mutex_unlock(&idescsi_ref_mutex); | ||
109 | return scsi; | ||
110 | } | ||
111 | |||
112 | static void ide_scsi_put(struct ide_scsi_obj *scsi) | ||
113 | { | ||
114 | ide_drive_t *drive = scsi->drive; | ||
115 | |||
116 | mutex_lock(&idescsi_ref_mutex); | ||
117 | scsi_host_put(scsi->host); | ||
118 | ide_device_put(drive); | ||
119 | mutex_unlock(&idescsi_ref_mutex); | ||
120 | } | ||
121 | |||
122 | static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host) | ||
123 | { | ||
124 | return (idescsi_scsi_t*) (&host[1]); | ||
125 | } | ||
126 | |||
127 | static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive) | ||
128 | { | ||
129 | return scsihost_to_idescsi(ide_drive->driver_data); | ||
130 | } | ||
131 | |||
132 | static void ide_scsi_hex_dump(u8 *data, int len) | ||
133 | { | ||
134 | print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, data, len, 0); | ||
135 | } | ||
136 | |||
137 | static int idescsi_end_request(ide_drive_t *, int, int); | ||
138 | |||
139 | static void ide_scsi_callback(ide_drive_t *drive, int dsc) | ||
140 | { | ||
141 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); | ||
142 | struct ide_atapi_pc *pc = drive->pc; | ||
143 | |||
144 | if (pc->flags & PC_FLAG_TIMEDOUT) | ||
145 | debug_log("%s: got timed out packet %lu at %lu\n", __func__, | ||
146 | pc->scsi_cmd->serial_number, jiffies); | ||
147 | /* end this request now - scsi should retry it*/ | ||
148 | else if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) | ||
149 | printk(KERN_INFO "Packet command completed, %d bytes" | ||
150 | " transferred\n", pc->xferred); | ||
151 | |||
152 | idescsi_end_request(drive, 1, 0); | ||
153 | } | ||
154 | |||
155 | static int idescsi_check_condition(ide_drive_t *drive, | ||
156 | struct request *failed_cmd) | ||
157 | { | ||
158 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); | ||
159 | struct ide_atapi_pc *pc; | ||
160 | struct request *rq; | ||
161 | u8 *buf; | ||
162 | |||
163 | /* stuff a sense request in front of our current request */ | ||
164 | pc = kzalloc(sizeof(struct ide_atapi_pc), GFP_ATOMIC); | ||
165 | rq = blk_get_request(drive->queue, READ, GFP_ATOMIC); | ||
166 | buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC); | ||
167 | if (!pc || !rq || !buf) { | ||
168 | kfree(buf); | ||
169 | if (rq) | ||
170 | blk_put_request(rq); | ||
171 | kfree(pc); | ||
172 | return -ENOMEM; | ||
173 | } | ||
174 | rq->special = (char *) pc; | ||
175 | pc->rq = rq; | ||
176 | pc->buf = buf; | ||
177 | pc->c[0] = REQUEST_SENSE; | ||
178 | pc->c[4] = pc->req_xfer = pc->buf_size = SCSI_SENSE_BUFFERSIZE; | ||
179 | rq->cmd_type = REQ_TYPE_SENSE; | ||
180 | rq->cmd_flags |= REQ_PREEMPT; | ||
181 | pc->timeout = jiffies + WAIT_READY; | ||
182 | /* NOTE! Save the failed packet command in "rq->buffer" */ | ||
183 | rq->buffer = (void *) failed_cmd->special; | ||
184 | pc->scsi_cmd = ((struct ide_atapi_pc *) failed_cmd->special)->scsi_cmd; | ||
185 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { | ||
186 | printk ("ide-scsi: %s: queue cmd = ", drive->name); | ||
187 | ide_scsi_hex_dump(pc->c, 6); | ||
188 | } | ||
189 | rq->rq_disk = scsi->disk; | ||
190 | rq->ref_count++; | ||
191 | memcpy(rq->cmd, pc->c, 12); | ||
192 | ide_do_drive_cmd(drive, rq); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static ide_startstop_t | ||
197 | idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) | ||
198 | { | ||
199 | ide_hwif_t *hwif = drive->hwif; | ||
200 | |||
201 | if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) | ||
202 | /* force an abort */ | ||
203 | hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE); | ||
204 | |||
205 | rq->errors++; | ||
206 | |||
207 | idescsi_end_request(drive, 0, 0); | ||
208 | |||
209 | return ide_stopped; | ||
210 | } | ||
211 | |||
212 | static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) | ||
213 | { | ||
214 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); | ||
215 | struct request *rq = HWGROUP(drive)->rq; | ||
216 | struct ide_atapi_pc *pc = (struct ide_atapi_pc *) rq->special; | ||
217 | int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); | ||
218 | struct Scsi_Host *host; | ||
219 | int errors = rq->errors; | ||
220 | unsigned long flags; | ||
221 | |||
222 | if (!blk_special_request(rq) && !blk_sense_request(rq)) { | ||
223 | ide_end_request(drive, uptodate, nrsecs); | ||
224 | return 0; | ||
225 | } | ||
226 | ide_end_drive_cmd (drive, 0, 0); | ||
227 | if (blk_sense_request(rq)) { | ||
228 | struct ide_atapi_pc *opc = (struct ide_atapi_pc *) rq->buffer; | ||
229 | if (log) { | ||
230 | printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number); | ||
231 | ide_scsi_hex_dump(pc->buf, 16); | ||
232 | } | ||
233 | memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buf, | ||
234 | SCSI_SENSE_BUFFERSIZE); | ||
235 | kfree(pc->buf); | ||
236 | kfree(pc); | ||
237 | blk_put_request(rq); | ||
238 | pc = opc; | ||
239 | rq = pc->rq; | ||
240 | pc->scsi_cmd->result = (CHECK_CONDITION << 1) | | ||
241 | (((pc->flags & PC_FLAG_TIMEDOUT) ? | ||
242 | DID_TIME_OUT : | ||
243 | DID_OK) << 16); | ||
244 | } else if (pc->flags & PC_FLAG_TIMEDOUT) { | ||
245 | if (log) | ||
246 | printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", | ||
247 | drive->name, pc->scsi_cmd->serial_number); | ||
248 | pc->scsi_cmd->result = DID_TIME_OUT << 16; | ||
249 | } else if (errors >= ERROR_MAX) { | ||
250 | pc->scsi_cmd->result = DID_ERROR << 16; | ||
251 | if (log) | ||
252 | printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); | ||
253 | } else if (errors) { | ||
254 | if (log) | ||
255 | printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); | ||
256 | if (!idescsi_check_condition(drive, rq)) | ||
257 | /* we started a request sense, so we'll be back, exit for now */ | ||
258 | return 0; | ||
259 | pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); | ||
260 | } else { | ||
261 | pc->scsi_cmd->result = DID_OK << 16; | ||
262 | } | ||
263 | host = pc->scsi_cmd->device->host; | ||
264 | spin_lock_irqsave(host->host_lock, flags); | ||
265 | pc->done(pc->scsi_cmd); | ||
266 | spin_unlock_irqrestore(host->host_lock, flags); | ||
267 | kfree(pc); | ||
268 | blk_put_request(rq); | ||
269 | drive->pc = NULL; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static inline int idescsi_set_direction(struct ide_atapi_pc *pc) | ||
274 | { | ||
275 | switch (pc->c[0]) { | ||
276 | case READ_6: case READ_10: case READ_12: | ||
277 | pc->flags &= ~PC_FLAG_WRITING; | ||
278 | return 0; | ||
279 | case WRITE_6: case WRITE_10: case WRITE_12: | ||
280 | pc->flags |= PC_FLAG_WRITING; | ||
281 | return 0; | ||
282 | default: | ||
283 | return 1; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static int idescsi_map_sg(ide_drive_t *drive, struct ide_atapi_pc *pc) | ||
288 | { | ||
289 | ide_hwif_t *hwif = drive->hwif; | ||
290 | struct scatterlist *sg, *scsi_sg; | ||
291 | int segments; | ||
292 | |||
293 | if (!pc->req_xfer || pc->req_xfer % 1024) | ||
294 | return 1; | ||
295 | |||
296 | if (idescsi_set_direction(pc)) | ||
297 | return 1; | ||
298 | |||
299 | sg = hwif->sg_table; | ||
300 | scsi_sg = scsi_sglist(pc->scsi_cmd); | ||
301 | segments = scsi_sg_count(pc->scsi_cmd); | ||
302 | |||
303 | if (segments > hwif->sg_max_nents) | ||
304 | return 1; | ||
305 | |||
306 | hwif->sg_nents = segments; | ||
307 | memcpy(sg, scsi_sg, sizeof(*sg) * segments); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive, | ||
313 | struct ide_atapi_pc *pc) | ||
314 | { | ||
315 | /* Set the current packet command */ | ||
316 | drive->pc = pc; | ||
317 | |||
318 | return ide_issue_pc(drive, ide_scsi_get_timeout(pc), ide_scsi_expiry); | ||
319 | } | ||
320 | |||
321 | /* | ||
322 | * idescsi_do_request is our request handling function. | ||
323 | */ | ||
324 | static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block) | ||
325 | { | ||
326 | debug_log("dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name, | ||
327 | rq->cmd[0], rq->errors); | ||
328 | debug_log("sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n", | ||
329 | rq->sector, rq->nr_sectors, rq->current_nr_sectors); | ||
330 | |||
331 | if (blk_sense_request(rq) || blk_special_request(rq)) { | ||
332 | struct ide_atapi_pc *pc = (struct ide_atapi_pc *)rq->special; | ||
333 | |||
334 | if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && | ||
335 | idescsi_map_sg(drive, pc) == 0) | ||
336 | pc->flags |= PC_FLAG_DMA_OK; | ||
337 | |||
338 | return idescsi_issue_pc(drive, pc); | ||
339 | } | ||
340 | blk_dump_rq_flags(rq, "ide-scsi: unsup command"); | ||
341 | idescsi_end_request (drive, 0, 0); | ||
342 | return ide_stopped; | ||
343 | } | ||
344 | |||
345 | #ifdef CONFIG_IDE_PROC_FS | ||
346 | static ide_proc_entry_t idescsi_proc[] = { | ||
347 | { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, | ||
348 | { NULL, 0, NULL, NULL } | ||
349 | }; | ||
350 | |||
351 | #define ide_scsi_devset_get(name, field) \ | ||
352 | static int get_##name(ide_drive_t *drive) \ | ||
353 | { \ | ||
354 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); \ | ||
355 | return scsi->field; \ | ||
356 | } | ||
357 | |||
358 | #define ide_scsi_devset_set(name, field) \ | ||
359 | static int set_##name(ide_drive_t *drive, int arg) \ | ||
360 | { \ | ||
361 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); \ | ||
362 | scsi->field = arg; \ | ||
363 | return 0; \ | ||
364 | } | ||
365 | |||
366 | #define ide_scsi_devset_rw_field(_name, _field) \ | ||
367 | ide_scsi_devset_get(_name, _field); \ | ||
368 | ide_scsi_devset_set(_name, _field); \ | ||
369 | IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name); | ||
370 | |||
371 | ide_devset_rw_field(bios_cyl, bios_cyl); | ||
372 | ide_devset_rw_field(bios_head, bios_head); | ||
373 | ide_devset_rw_field(bios_sect, bios_sect); | ||
374 | |||
375 | ide_scsi_devset_rw_field(transform, transform); | ||
376 | ide_scsi_devset_rw_field(log, log); | ||
377 | |||
378 | static const struct ide_proc_devset idescsi_settings[] = { | ||
379 | IDE_PROC_DEVSET(bios_cyl, 0, 1023), | ||
380 | IDE_PROC_DEVSET(bios_head, 0, 255), | ||
381 | IDE_PROC_DEVSET(bios_sect, 0, 63), | ||
382 | IDE_PROC_DEVSET(log, 0, 1), | ||
383 | IDE_PROC_DEVSET(transform, 0, 3), | ||
384 | { 0 }, | ||
385 | }; | ||
386 | |||
387 | static ide_proc_entry_t *ide_scsi_proc_entries(ide_drive_t *drive) | ||
388 | { | ||
389 | return idescsi_proc; | ||
390 | } | ||
391 | |||
392 | static const struct ide_proc_devset *ide_scsi_proc_devsets(ide_drive_t *drive) | ||
393 | { | ||
394 | return idescsi_settings; | ||
395 | } | ||
396 | #endif | ||
397 | |||
398 | /* | ||
399 | * Driver initialization. | ||
400 | */ | ||
401 | static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi) | ||
402 | { | ||
403 | clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); | ||
404 | #if IDESCSI_DEBUG_LOG | ||
405 | set_bit(IDESCSI_LOG_CMD, &scsi->log); | ||
406 | #endif /* IDESCSI_DEBUG_LOG */ | ||
407 | |||
408 | drive->pc_callback = ide_scsi_callback; | ||
409 | drive->pc_update_buffers = NULL; | ||
410 | drive->pc_io_buffers = ide_io_buffers; | ||
411 | |||
412 | ide_proc_register_driver(drive, scsi->driver); | ||
413 | } | ||
414 | |||
415 | static void ide_scsi_remove(ide_drive_t *drive) | ||
416 | { | ||
417 | struct Scsi_Host *scsihost = drive->driver_data; | ||
418 | struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost); | ||
419 | struct gendisk *g = scsi->disk; | ||
420 | |||
421 | scsi_remove_host(scsihost); | ||
422 | ide_proc_unregister_driver(drive, scsi->driver); | ||
423 | |||
424 | ide_unregister_region(g); | ||
425 | |||
426 | drive->driver_data = NULL; | ||
427 | g->private_data = NULL; | ||
428 | put_disk(g); | ||
429 | |||
430 | ide_scsi_put(scsi); | ||
431 | |||
432 | drive->dev_flags &= ~IDE_DFLAG_SCSI; | ||
433 | } | ||
434 | |||
435 | static int ide_scsi_probe(ide_drive_t *); | ||
436 | |||
437 | static ide_driver_t idescsi_driver = { | ||
438 | .gen_driver = { | ||
439 | .owner = THIS_MODULE, | ||
440 | .name = "ide-scsi", | ||
441 | .bus = &ide_bus_type, | ||
442 | }, | ||
443 | .probe = ide_scsi_probe, | ||
444 | .remove = ide_scsi_remove, | ||
445 | .version = IDESCSI_VERSION, | ||
446 | .do_request = idescsi_do_request, | ||
447 | .end_request = idescsi_end_request, | ||
448 | .error = idescsi_atapi_error, | ||
449 | #ifdef CONFIG_IDE_PROC_FS | ||
450 | .proc_entries = ide_scsi_proc_entries, | ||
451 | .proc_devsets = ide_scsi_proc_devsets, | ||
452 | #endif | ||
453 | }; | ||
454 | |||
455 | static int idescsi_ide_open(struct block_device *bdev, fmode_t mode) | ||
456 | { | ||
457 | struct ide_scsi_obj *scsi = ide_scsi_get(bdev->bd_disk); | ||
458 | |||
459 | if (!scsi) | ||
460 | return -ENXIO; | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int idescsi_ide_release(struct gendisk *disk, fmode_t mode) | ||
466 | { | ||
467 | ide_scsi_put(ide_scsi_g(disk)); | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int idescsi_ide_ioctl(struct block_device *bdev, fmode_t mode, | ||
472 | unsigned int cmd, unsigned long arg) | ||
473 | { | ||
474 | struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk); | ||
475 | return generic_ide_ioctl(scsi->drive, bdev, cmd, arg); | ||
476 | } | ||
477 | |||
478 | static struct block_device_operations idescsi_ops = { | ||
479 | .owner = THIS_MODULE, | ||
480 | .open = idescsi_ide_open, | ||
481 | .release = idescsi_ide_release, | ||
482 | .locked_ioctl = idescsi_ide_ioctl, | ||
483 | }; | ||
484 | |||
485 | static int idescsi_slave_configure(struct scsi_device * sdp) | ||
486 | { | ||
487 | /* Configure detected device */ | ||
488 | sdp->use_10_for_rw = 1; | ||
489 | sdp->use_10_for_ms = 1; | ||
490 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun); | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static const char *idescsi_info (struct Scsi_Host *host) | ||
495 | { | ||
496 | return "SCSI host adapter emulation for IDE ATAPI devices"; | ||
497 | } | ||
498 | |||
499 | static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg) | ||
500 | { | ||
501 | idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host); | ||
502 | |||
503 | if (cmd == SG_SET_TRANSFORM) { | ||
504 | if (arg) | ||
505 | set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); | ||
506 | else | ||
507 | clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); | ||
508 | return 0; | ||
509 | } else if (cmd == SG_GET_TRANSFORM) | ||
510 | return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int __user *) arg); | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | |||
514 | static int idescsi_queue (struct scsi_cmnd *cmd, | ||
515 | void (*done)(struct scsi_cmnd *)) | ||
516 | { | ||
517 | struct Scsi_Host *host = cmd->device->host; | ||
518 | idescsi_scsi_t *scsi = scsihost_to_idescsi(host); | ||
519 | ide_drive_t *drive = scsi->drive; | ||
520 | struct request *rq = NULL; | ||
521 | struct ide_atapi_pc *pc = NULL; | ||
522 | int write = cmd->sc_data_direction == DMA_TO_DEVICE; | ||
523 | |||
524 | if (!drive) { | ||
525 | scmd_printk (KERN_ERR, cmd, "drive not present\n"); | ||
526 | goto abort; | ||
527 | } | ||
528 | scsi = drive_to_idescsi(drive); | ||
529 | pc = kmalloc(sizeof(struct ide_atapi_pc), GFP_ATOMIC); | ||
530 | rq = blk_get_request(drive->queue, write, GFP_ATOMIC); | ||
531 | if (rq == NULL || pc == NULL) { | ||
532 | printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name); | ||
533 | goto abort; | ||
534 | } | ||
535 | |||
536 | memset (pc->c, 0, 12); | ||
537 | pc->flags = 0; | ||
538 | if (cmd->sc_data_direction == DMA_TO_DEVICE) | ||
539 | pc->flags |= PC_FLAG_WRITING; | ||
540 | pc->rq = rq; | ||
541 | memcpy (pc->c, cmd->cmnd, cmd->cmd_len); | ||
542 | pc->buf = NULL; | ||
543 | pc->sg = scsi_sglist(cmd); | ||
544 | pc->sg_cnt = scsi_sg_count(cmd); | ||
545 | pc->b_count = 0; | ||
546 | pc->req_xfer = pc->buf_size = scsi_bufflen(cmd); | ||
547 | pc->scsi_cmd = cmd; | ||
548 | pc->done = done; | ||
549 | pc->timeout = jiffies + cmd->request->timeout; | ||
550 | |||
551 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { | ||
552 | printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); | ||
553 | ide_scsi_hex_dump(cmd->cmnd, cmd->cmd_len); | ||
554 | if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) { | ||
555 | printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number); | ||
556 | ide_scsi_hex_dump(pc->c, 12); | ||
557 | } | ||
558 | } | ||
559 | |||
560 | rq->special = (char *) pc; | ||
561 | rq->cmd_type = REQ_TYPE_SPECIAL; | ||
562 | spin_unlock_irq(host->host_lock); | ||
563 | rq->ref_count++; | ||
564 | memcpy(rq->cmd, pc->c, 12); | ||
565 | blk_execute_rq_nowait(drive->queue, scsi->disk, rq, 0, NULL); | ||
566 | spin_lock_irq(host->host_lock); | ||
567 | return 0; | ||
568 | abort: | ||
569 | kfree (pc); | ||
570 | if (rq) | ||
571 | blk_put_request(rq); | ||
572 | cmd->result = DID_ERROR << 16; | ||
573 | done(cmd); | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int idescsi_eh_abort (struct scsi_cmnd *cmd) | ||
578 | { | ||
579 | idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); | ||
580 | ide_drive_t *drive = scsi->drive; | ||
581 | ide_hwif_t *hwif; | ||
582 | ide_hwgroup_t *hwgroup; | ||
583 | int busy; | ||
584 | int ret = FAILED; | ||
585 | |||
586 | struct ide_atapi_pc *pc; | ||
587 | |||
588 | /* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */ | ||
589 | |||
590 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) | ||
591 | printk (KERN_WARNING "ide-scsi: abort called for %lu\n", cmd->serial_number); | ||
592 | |||
593 | if (!drive) { | ||
594 | printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_abort\n"); | ||
595 | WARN_ON(1); | ||
596 | goto no_drive; | ||
597 | } | ||
598 | |||
599 | hwif = drive->hwif; | ||
600 | hwgroup = hwif->hwgroup; | ||
601 | |||
602 | /* First give it some more time, how much is "right" is hard to say :-( | ||
603 | FIXME - uses mdelay which causes latency? */ | ||
604 | busy = ide_wait_not_busy(hwif, 100); | ||
605 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) | ||
606 | printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":""); | ||
607 | |||
608 | spin_lock_irq(&hwgroup->lock); | ||
609 | |||
610 | /* If there is no pc running we're done (our interrupt took care of it) */ | ||
611 | pc = drive->pc; | ||
612 | if (pc == NULL) { | ||
613 | ret = SUCCESS; | ||
614 | goto ide_unlock; | ||
615 | } | ||
616 | |||
617 | /* It's somewhere in flight. Does ide subsystem agree? */ | ||
618 | if (pc->scsi_cmd->serial_number == cmd->serial_number && !busy && | ||
619 | elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != pc->rq) { | ||
620 | /* | ||
621 | * FIXME - not sure this condition can ever occur | ||
622 | */ | ||
623 | printk (KERN_ERR "ide-scsi: cmd aborted!\n"); | ||
624 | |||
625 | if (blk_sense_request(pc->rq)) | ||
626 | kfree(pc->buf); | ||
627 | /* we need to call blk_put_request twice. */ | ||
628 | blk_put_request(pc->rq); | ||
629 | blk_put_request(pc->rq); | ||
630 | kfree(pc); | ||
631 | drive->pc = NULL; | ||
632 | |||
633 | ret = SUCCESS; | ||
634 | } | ||
635 | |||
636 | ide_unlock: | ||
637 | spin_unlock_irq(&hwgroup->lock); | ||
638 | no_drive: | ||
639 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) | ||
640 | printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed"); | ||
641 | |||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | static int idescsi_eh_reset (struct scsi_cmnd *cmd) | ||
646 | { | ||
647 | struct request *req; | ||
648 | idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); | ||
649 | ide_drive_t *drive = scsi->drive; | ||
650 | ide_hwgroup_t *hwgroup; | ||
651 | int ready = 0; | ||
652 | int ret = SUCCESS; | ||
653 | |||
654 | struct ide_atapi_pc *pc; | ||
655 | |||
656 | /* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */ | ||
657 | |||
658 | if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) | ||
659 | printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number); | ||
660 | |||
661 | if (!drive) { | ||
662 | printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n"); | ||
663 | WARN_ON(1); | ||
664 | return FAILED; | ||
665 | } | ||
666 | |||
667 | hwgroup = drive->hwif->hwgroup; | ||
668 | |||
669 | spin_lock_irq(cmd->device->host->host_lock); | ||
670 | spin_lock(&hwgroup->lock); | ||
671 | |||
672 | pc = drive->pc; | ||
673 | if (pc) | ||
674 | req = pc->rq; | ||
675 | |||
676 | if (pc == NULL || req != hwgroup->rq || hwgroup->handler == NULL) { | ||
677 | printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n"); | ||
678 | spin_unlock(&hwgroup->lock); | ||
679 | spin_unlock_irq(cmd->device->host->host_lock); | ||
680 | return FAILED; | ||
681 | } | ||
682 | |||
683 | /* kill current request */ | ||
684 | if (__blk_end_request(req, -EIO, 0)) | ||
685 | BUG(); | ||
686 | if (blk_sense_request(req)) | ||
687 | kfree(pc->buf); | ||
688 | kfree(pc); | ||
689 | drive->pc = NULL; | ||
690 | blk_put_request(req); | ||
691 | |||
692 | /* now nuke the drive queue */ | ||
693 | while ((req = elv_next_request(drive->queue))) { | ||
694 | if (__blk_end_request(req, -EIO, 0)) | ||
695 | BUG(); | ||
696 | } | ||
697 | |||
698 | hwgroup->rq = NULL; | ||
699 | hwgroup->handler = NULL; | ||
700 | hwgroup->busy = 1; /* will set this to zero when ide reset finished */ | ||
701 | spin_unlock(&hwgroup->lock); | ||
702 | |||
703 | ide_do_reset(drive); | ||
704 | |||
705 | /* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */ | ||
706 | |||
707 | do { | ||
708 | spin_unlock_irq(cmd->device->host->host_lock); | ||
709 | msleep(50); | ||
710 | spin_lock_irq(cmd->device->host->host_lock); | ||
711 | } while ( HWGROUP(drive)->handler ); | ||
712 | |||
713 | ready = drive_is_ready(drive); | ||
714 | HWGROUP(drive)->busy--; | ||
715 | if (!ready) { | ||
716 | printk (KERN_ERR "ide-scsi: reset failed!\n"); | ||
717 | ret = FAILED; | ||
718 | } | ||
719 | |||
720 | spin_unlock_irq(cmd->device->host->host_lock); | ||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev, | ||
725 | sector_t capacity, int *parm) | ||
726 | { | ||
727 | idescsi_scsi_t *idescsi = scsihost_to_idescsi(sdev->host); | ||
728 | ide_drive_t *drive = idescsi->drive; | ||
729 | |||
730 | if (drive->bios_cyl && drive->bios_head && drive->bios_sect) { | ||
731 | parm[0] = drive->bios_head; | ||
732 | parm[1] = drive->bios_sect; | ||
733 | parm[2] = drive->bios_cyl; | ||
734 | } | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static struct scsi_host_template idescsi_template = { | ||
739 | .module = THIS_MODULE, | ||
740 | .name = "idescsi", | ||
741 | .info = idescsi_info, | ||
742 | .slave_configure = idescsi_slave_configure, | ||
743 | .ioctl = idescsi_ioctl, | ||
744 | .queuecommand = idescsi_queue, | ||
745 | .eh_abort_handler = idescsi_eh_abort, | ||
746 | .eh_host_reset_handler = idescsi_eh_reset, | ||
747 | .bios_param = idescsi_bios, | ||
748 | .can_queue = 40, | ||
749 | .this_id = -1, | ||
750 | .sg_tablesize = 256, | ||
751 | .cmd_per_lun = 5, | ||
752 | .max_sectors = 128, | ||
753 | .use_clustering = DISABLE_CLUSTERING, | ||
754 | .emulated = 1, | ||
755 | .proc_name = "ide-scsi", | ||
756 | }; | ||
757 | |||
758 | static int ide_scsi_probe(ide_drive_t *drive) | ||
759 | { | ||
760 | idescsi_scsi_t *idescsi; | ||
761 | struct Scsi_Host *host; | ||
762 | struct gendisk *g; | ||
763 | static int warned; | ||
764 | int err = -ENOMEM; | ||
765 | u16 last_lun; | ||
766 | |||
767 | if (!warned && drive->media == ide_cdrom) { | ||
768 | printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n"); | ||
769 | warned = 1; | ||
770 | } | ||
771 | |||
772 | if (idescsi_nocd && drive->media == ide_cdrom) | ||
773 | return -ENODEV; | ||
774 | |||
775 | if (!strstr("ide-scsi", drive->driver_req) || | ||
776 | drive->media == ide_disk || | ||
777 | !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t)))) | ||
778 | return -ENODEV; | ||
779 | |||
780 | drive->dev_flags |= IDE_DFLAG_SCSI; | ||
781 | |||
782 | g = alloc_disk(1 << PARTN_BITS); | ||
783 | if (!g) | ||
784 | goto out_host_put; | ||
785 | |||
786 | ide_init_disk(g, drive); | ||
787 | |||
788 | host->max_id = 1; | ||
789 | |||
790 | last_lun = drive->id[ATA_ID_LAST_LUN]; | ||
791 | if (last_lun) | ||
792 | debug_log("%s: last_lun=%u\n", drive->name, last_lun); | ||
793 | |||
794 | if ((last_lun & 7) != 7) | ||
795 | host->max_lun = (last_lun & 7) + 1; | ||
796 | else | ||
797 | host->max_lun = 1; | ||
798 | |||
799 | drive->driver_data = host; | ||
800 | idescsi = scsihost_to_idescsi(host); | ||
801 | idescsi->drive = drive; | ||
802 | idescsi->driver = &idescsi_driver; | ||
803 | idescsi->host = host; | ||
804 | idescsi->disk = g; | ||
805 | g->private_data = &idescsi->driver; | ||
806 | err = 0; | ||
807 | idescsi_setup(drive, idescsi); | ||
808 | g->fops = &idescsi_ops; | ||
809 | ide_register_region(g); | ||
810 | err = scsi_add_host(host, &drive->gendev); | ||
811 | if (!err) { | ||
812 | scsi_scan_host(host); | ||
813 | return 0; | ||
814 | } | ||
815 | /* fall through on error */ | ||
816 | ide_unregister_region(g); | ||
817 | ide_proc_unregister_driver(drive, &idescsi_driver); | ||
818 | |||
819 | put_disk(g); | ||
820 | out_host_put: | ||
821 | drive->dev_flags &= ~IDE_DFLAG_SCSI; | ||
822 | scsi_host_put(host); | ||
823 | return err; | ||
824 | } | ||
825 | |||
826 | static int __init init_idescsi_module(void) | ||
827 | { | ||
828 | return driver_register(&idescsi_driver.gen_driver); | ||
829 | } | ||
830 | |||
831 | static void __exit exit_idescsi_module(void) | ||
832 | { | ||
833 | driver_unregister(&idescsi_driver.gen_driver); | ||
834 | } | ||
835 | |||
836 | module_param(idescsi_nocd, int, 0600); | ||
837 | MODULE_PARM_DESC(idescsi_nocd, "Disable handling of CD-ROMs so they may be driven by ide-cd"); | ||
838 | module_init(init_idescsi_module); | ||
839 | module_exit(exit_idescsi_module); | ||
840 | MODULE_LICENSE("GPL"); | ||