Commit | Line | Data |
---|---|---|
115bb1ff MW |
1 | /* |
2 | * USB Attached SCSI | |
3 | * Note that this is not the same as the USB Mass Storage driver | |
4 | * | |
5 | * Copyright Matthew Wilcox for Intel Corp, 2010 | |
6 | * Copyright Sarah Sharp for Intel Corp, 2010 | |
7 | * | |
8 | * Distributed under the terms of the GNU GPL, version two. | |
9 | */ | |
10 | ||
11 | #include <linux/blkdev.h> | |
12 | #include <linux/slab.h> | |
13 | #include <linux/types.h> | |
6eb0de82 | 14 | #include <linux/module.h> |
115bb1ff MW |
15 | #include <linux/usb.h> |
16 | #include <linux/usb/storage.h> | |
17 | ||
18 | #include <scsi/scsi.h> | |
19 | #include <scsi/scsi_dbg.h> | |
20 | #include <scsi/scsi_cmnd.h> | |
21 | #include <scsi/scsi_device.h> | |
22 | #include <scsi/scsi_host.h> | |
23 | #include <scsi/scsi_tcq.h> | |
24 | ||
25 | /* Common header for all IUs */ | |
26 | struct iu { | |
27 | __u8 iu_id; | |
28 | __u8 rsvd1; | |
29 | __be16 tag; | |
30 | }; | |
31 | ||
32 | enum { | |
33 | IU_ID_COMMAND = 0x01, | |
34 | IU_ID_STATUS = 0x03, | |
35 | IU_ID_RESPONSE = 0x04, | |
36 | IU_ID_TASK_MGMT = 0x05, | |
37 | IU_ID_READ_READY = 0x06, | |
38 | IU_ID_WRITE_READY = 0x07, | |
39 | }; | |
40 | ||
41 | struct command_iu { | |
42 | __u8 iu_id; | |
43 | __u8 rsvd1; | |
44 | __be16 tag; | |
45 | __u8 prio_attr; | |
46 | __u8 rsvd5; | |
47 | __u8 len; | |
48 | __u8 rsvd7; | |
49 | struct scsi_lun lun; | |
50 | __u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */ | |
51 | }; | |
52 | ||
4400ef31 MW |
53 | /* |
54 | * Also used for the Read Ready and Write Ready IUs since they have the | |
55 | * same first four bytes | |
56 | */ | |
115bb1ff MW |
57 | struct sense_iu { |
58 | __u8 iu_id; | |
59 | __u8 rsvd1; | |
60 | __be16 tag; | |
61 | __be16 status_qual; | |
62 | __u8 status; | |
4400ef31 | 63 | __u8 rsvd7[7]; |
115bb1ff MW |
64 | __be16 len; |
65 | __u8 sense[SCSI_SENSE_BUFFERSIZE]; | |
66 | }; | |
67 | ||
68 | /* | |
69 | * The r00-r01c specs define this version of the SENSE IU data structure. | |
70 | * It's still in use by several different firmware releases. | |
71 | */ | |
72 | struct sense_iu_old { | |
73 | __u8 iu_id; | |
74 | __u8 rsvd1; | |
75 | __be16 tag; | |
76 | __be16 len; | |
77 | __u8 status; | |
78 | __u8 service_response; | |
79 | __u8 sense[SCSI_SENSE_BUFFERSIZE]; | |
80 | }; | |
81 | ||
82 | enum { | |
83 | CMD_PIPE_ID = 1, | |
84 | STATUS_PIPE_ID = 2, | |
85 | DATA_IN_PIPE_ID = 3, | |
86 | DATA_OUT_PIPE_ID = 4, | |
87 | ||
88 | UAS_SIMPLE_TAG = 0, | |
89 | UAS_HEAD_TAG = 1, | |
90 | UAS_ORDERED_TAG = 2, | |
91 | UAS_ACA = 4, | |
92 | }; | |
93 | ||
94 | struct uas_dev_info { | |
95 | struct usb_interface *intf; | |
96 | struct usb_device *udev; | |
97 | int qdepth; | |
98 | unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; | |
99 | unsigned use_streams:1; | |
100 | unsigned uas_sense_old:1; | |
101 | }; | |
102 | ||
103 | enum { | |
92a3f767 MW |
104 | ALLOC_STATUS_URB = (1 << 0), |
105 | SUBMIT_STATUS_URB = (1 << 1), | |
115bb1ff MW |
106 | ALLOC_DATA_IN_URB = (1 << 2), |
107 | SUBMIT_DATA_IN_URB = (1 << 3), | |
108 | ALLOC_DATA_OUT_URB = (1 << 4), | |
109 | SUBMIT_DATA_OUT_URB = (1 << 5), | |
110 | ALLOC_CMD_URB = (1 << 6), | |
111 | SUBMIT_CMD_URB = (1 << 7), | |
112 | }; | |
113 | ||
114 | /* Overrides scsi_pointer */ | |
115 | struct uas_cmd_info { | |
116 | unsigned int state; | |
117 | unsigned int stream; | |
118 | struct urb *cmd_urb; | |
92a3f767 | 119 | struct urb *status_urb; |
115bb1ff MW |
120 | struct urb *data_in_urb; |
121 | struct urb *data_out_urb; | |
122 | struct list_head list; | |
123 | }; | |
124 | ||
125 | /* I hate forward declarations, but I actually have a loop */ | |
126 | static int uas_submit_urbs(struct scsi_cmnd *cmnd, | |
127 | struct uas_dev_info *devinfo, gfp_t gfp); | |
ea9da1c7 | 128 | static void uas_do_work(struct work_struct *work); |
115bb1ff | 129 | |
ea9da1c7 | 130 | static DECLARE_WORK(uas_work, uas_do_work); |
115bb1ff MW |
131 | static DEFINE_SPINLOCK(uas_work_lock); |
132 | static LIST_HEAD(uas_work_list); | |
133 | ||
134 | static void uas_do_work(struct work_struct *work) | |
135 | { | |
136 | struct uas_cmd_info *cmdinfo; | |
ea9da1c7 | 137 | struct uas_cmd_info *temp; |
115bb1ff | 138 | struct list_head list; |
ea9da1c7 | 139 | int err; |
115bb1ff MW |
140 | |
141 | spin_lock_irq(&uas_work_lock); | |
142 | list_replace_init(&uas_work_list, &list); | |
143 | spin_unlock_irq(&uas_work_lock); | |
144 | ||
ea9da1c7 | 145 | list_for_each_entry_safe(cmdinfo, temp, &list, list) { |
115bb1ff MW |
146 | struct scsi_pointer *scp = (void *)cmdinfo; |
147 | struct scsi_cmnd *cmnd = container_of(scp, | |
148 | struct scsi_cmnd, SCp); | |
ea9da1c7 SS |
149 | err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); |
150 | if (err) { | |
151 | list_del(&cmdinfo->list); | |
152 | spin_lock_irq(&uas_work_lock); | |
153 | list_add_tail(&cmdinfo->list, &uas_work_list); | |
154 | spin_unlock_irq(&uas_work_lock); | |
155 | schedule_work(&uas_work); | |
156 | } | |
115bb1ff MW |
157 | } |
158 | } | |
159 | ||
115bb1ff MW |
160 | static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) |
161 | { | |
162 | struct sense_iu *sense_iu = urb->transfer_buffer; | |
163 | struct scsi_device *sdev = cmnd->device; | |
164 | ||
165 | if (urb->actual_length > 16) { | |
166 | unsigned len = be16_to_cpup(&sense_iu->len); | |
167 | if (len + 16 != urb->actual_length) { | |
168 | int newlen = min(len + 16, urb->actual_length) - 16; | |
169 | if (newlen < 0) | |
170 | newlen = 0; | |
171 | sdev_printk(KERN_INFO, sdev, "%s: urb length %d " | |
172 | "disagrees with IU sense data length %d, " | |
173 | "using %d bytes of sense data\n", __func__, | |
174 | urb->actual_length, len, newlen); | |
175 | len = newlen; | |
176 | } | |
177 | memcpy(cmnd->sense_buffer, sense_iu->sense, len); | |
178 | } | |
179 | ||
180 | cmnd->result = sense_iu->status; | |
181 | if (sdev->current_cmnd) | |
182 | sdev->current_cmnd = NULL; | |
183 | cmnd->scsi_done(cmnd); | |
184 | usb_free_urb(urb); | |
185 | } | |
186 | ||
187 | static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) | |
188 | { | |
189 | struct sense_iu_old *sense_iu = urb->transfer_buffer; | |
190 | struct scsi_device *sdev = cmnd->device; | |
191 | ||
192 | if (urb->actual_length > 8) { | |
193 | unsigned len = be16_to_cpup(&sense_iu->len) - 2; | |
194 | if (len + 8 != urb->actual_length) { | |
195 | int newlen = min(len + 8, urb->actual_length) - 8; | |
196 | if (newlen < 0) | |
197 | newlen = 0; | |
198 | sdev_printk(KERN_INFO, sdev, "%s: urb length %d " | |
199 | "disagrees with IU sense data length %d, " | |
200 | "using %d bytes of sense data\n", __func__, | |
201 | urb->actual_length, len, newlen); | |
202 | len = newlen; | |
203 | } | |
204 | memcpy(cmnd->sense_buffer, sense_iu->sense, len); | |
205 | } | |
206 | ||
207 | cmnd->result = sense_iu->status; | |
208 | if (sdev->current_cmnd) | |
209 | sdev->current_cmnd = NULL; | |
210 | cmnd->scsi_done(cmnd); | |
211 | usb_free_urb(urb); | |
212 | } | |
213 | ||
214 | static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, | |
215 | unsigned direction) | |
216 | { | |
217 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | |
218 | int err; | |
219 | ||
92a3f767 | 220 | cmdinfo->state = direction | SUBMIT_STATUS_URB; |
115bb1ff MW |
221 | err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); |
222 | if (err) { | |
223 | spin_lock(&uas_work_lock); | |
224 | list_add_tail(&cmdinfo->list, &uas_work_list); | |
225 | spin_unlock(&uas_work_lock); | |
226 | schedule_work(&uas_work); | |
227 | } | |
228 | } | |
229 | ||
230 | static void uas_stat_cmplt(struct urb *urb) | |
231 | { | |
232 | struct iu *iu = urb->transfer_buffer; | |
233 | struct scsi_device *sdev = urb->context; | |
234 | struct uas_dev_info *devinfo = sdev->hostdata; | |
235 | struct scsi_cmnd *cmnd; | |
236 | u16 tag; | |
237 | ||
238 | if (urb->status) { | |
239 | dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); | |
240 | usb_free_urb(urb); | |
241 | return; | |
242 | } | |
243 | ||
244 | tag = be16_to_cpup(&iu->tag) - 1; | |
245 | if (sdev->current_cmnd) | |
246 | cmnd = sdev->current_cmnd; | |
247 | else | |
248 | cmnd = scsi_find_tag(sdev, tag); | |
96c1eb98 SS |
249 | if (!cmnd) { |
250 | usb_free_urb(urb); | |
115bb1ff | 251 | return; |
96c1eb98 | 252 | } |
115bb1ff MW |
253 | |
254 | switch (iu->iu_id) { | |
255 | case IU_ID_STATUS: | |
256 | if (urb->actual_length < 16) | |
257 | devinfo->uas_sense_old = 1; | |
258 | if (devinfo->uas_sense_old) | |
259 | uas_sense_old(urb, cmnd); | |
260 | else | |
261 | uas_sense(urb, cmnd); | |
262 | break; | |
263 | case IU_ID_READ_READY: | |
264 | uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB); | |
265 | break; | |
266 | case IU_ID_WRITE_READY: | |
267 | uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB); | |
268 | break; | |
269 | default: | |
270 | scmd_printk(KERN_ERR, cmnd, | |
271 | "Bogus IU (%d) received on status pipe\n", iu->iu_id); | |
272 | } | |
273 | } | |
274 | ||
275 | static void uas_data_cmplt(struct urb *urb) | |
276 | { | |
277 | struct scsi_data_buffer *sdb = urb->context; | |
278 | sdb->resid = sdb->length - urb->actual_length; | |
279 | usb_free_urb(urb); | |
280 | } | |
281 | ||
282 | static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |
283 | unsigned int pipe, u16 stream_id, | |
284 | struct scsi_data_buffer *sdb, | |
285 | enum dma_data_direction dir) | |
286 | { | |
287 | struct usb_device *udev = devinfo->udev; | |
288 | struct urb *urb = usb_alloc_urb(0, gfp); | |
289 | ||
290 | if (!urb) | |
291 | goto out; | |
292 | usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, | |
293 | sdb); | |
294 | if (devinfo->use_streams) | |
295 | urb->stream_id = stream_id; | |
296 | urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; | |
297 | urb->sg = sdb->table.sgl; | |
298 | out: | |
299 | return urb; | |
300 | } | |
301 | ||
302 | static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |
303 | struct scsi_cmnd *cmnd, u16 stream_id) | |
304 | { | |
305 | struct usb_device *udev = devinfo->udev; | |
306 | struct urb *urb = usb_alloc_urb(0, gfp); | |
307 | struct sense_iu *iu; | |
308 | ||
309 | if (!urb) | |
310 | goto out; | |
311 | ||
ac563cfd | 312 | iu = kzalloc(sizeof(*iu), gfp); |
115bb1ff MW |
313 | if (!iu) |
314 | goto free; | |
315 | ||
316 | usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), | |
317 | uas_stat_cmplt, cmnd->device); | |
318 | urb->stream_id = stream_id; | |
319 | urb->transfer_flags |= URB_FREE_BUFFER; | |
320 | out: | |
321 | return urb; | |
322 | free: | |
323 | usb_free_urb(urb); | |
324 | return NULL; | |
325 | } | |
326 | ||
327 | static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, | |
328 | struct scsi_cmnd *cmnd, u16 stream_id) | |
329 | { | |
330 | struct usb_device *udev = devinfo->udev; | |
331 | struct scsi_device *sdev = cmnd->device; | |
332 | struct urb *urb = usb_alloc_urb(0, gfp); | |
333 | struct command_iu *iu; | |
334 | int len; | |
335 | ||
336 | if (!urb) | |
337 | goto out; | |
338 | ||
339 | len = cmnd->cmd_len - 16; | |
340 | if (len < 0) | |
341 | len = 0; | |
342 | len = ALIGN(len, 4); | |
ac563cfd | 343 | iu = kzalloc(sizeof(*iu) + len, gfp); |
115bb1ff MW |
344 | if (!iu) |
345 | goto free; | |
346 | ||
347 | iu->iu_id = IU_ID_COMMAND; | |
9eb44541 SS |
348 | if (blk_rq_tagged(cmnd->request)) |
349 | iu->tag = cpu_to_be16(cmnd->request->tag + 1); | |
350 | else | |
351 | iu->tag = cpu_to_be16(1); | |
02e031cb | 352 | iu->prio_attr = UAS_SIMPLE_TAG; |
115bb1ff MW |
353 | iu->len = len; |
354 | int_to_scsilun(sdev->lun, &iu->lun); | |
355 | memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len); | |
356 | ||
357 | usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len, | |
358 | usb_free_urb, NULL); | |
359 | urb->transfer_flags |= URB_FREE_BUFFER; | |
360 | out: | |
361 | return urb; | |
362 | free: | |
363 | usb_free_urb(urb); | |
364 | return NULL; | |
365 | } | |
366 | ||
367 | /* | |
368 | * Why should I request the Status IU before sending the Command IU? Spec | |
369 | * says to, but also says the device may receive them in any order. Seems | |
370 | * daft to me. | |
371 | */ | |
372 | ||
373 | static int uas_submit_urbs(struct scsi_cmnd *cmnd, | |
374 | struct uas_dev_info *devinfo, gfp_t gfp) | |
375 | { | |
376 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | |
377 | ||
92a3f767 MW |
378 | if (cmdinfo->state & ALLOC_STATUS_URB) { |
379 | cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd, | |
380 | cmdinfo->stream); | |
381 | if (!cmdinfo->status_urb) | |
115bb1ff | 382 | return SCSI_MLQUEUE_DEVICE_BUSY; |
92a3f767 | 383 | cmdinfo->state &= ~ALLOC_STATUS_URB; |
115bb1ff MW |
384 | } |
385 | ||
92a3f767 MW |
386 | if (cmdinfo->state & SUBMIT_STATUS_URB) { |
387 | if (usb_submit_urb(cmdinfo->status_urb, gfp)) { | |
115bb1ff MW |
388 | scmd_printk(KERN_INFO, cmnd, |
389 | "sense urb submission failure\n"); | |
390 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
391 | } | |
92a3f767 | 392 | cmdinfo->state &= ~SUBMIT_STATUS_URB; |
115bb1ff MW |
393 | } |
394 | ||
395 | if (cmdinfo->state & ALLOC_DATA_IN_URB) { | |
396 | cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, | |
397 | devinfo->data_in_pipe, cmdinfo->stream, | |
398 | scsi_in(cmnd), DMA_FROM_DEVICE); | |
399 | if (!cmdinfo->data_in_urb) | |
400 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
401 | cmdinfo->state &= ~ALLOC_DATA_IN_URB; | |
402 | } | |
403 | ||
404 | if (cmdinfo->state & SUBMIT_DATA_IN_URB) { | |
405 | if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) { | |
406 | scmd_printk(KERN_INFO, cmnd, | |
407 | "data in urb submission failure\n"); | |
408 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
409 | } | |
410 | cmdinfo->state &= ~SUBMIT_DATA_IN_URB; | |
411 | } | |
412 | ||
413 | if (cmdinfo->state & ALLOC_DATA_OUT_URB) { | |
414 | cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, | |
415 | devinfo->data_out_pipe, cmdinfo->stream, | |
416 | scsi_out(cmnd), DMA_TO_DEVICE); | |
417 | if (!cmdinfo->data_out_urb) | |
418 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
419 | cmdinfo->state &= ~ALLOC_DATA_OUT_URB; | |
420 | } | |
421 | ||
422 | if (cmdinfo->state & SUBMIT_DATA_OUT_URB) { | |
423 | if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) { | |
424 | scmd_printk(KERN_INFO, cmnd, | |
425 | "data out urb submission failure\n"); | |
426 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
427 | } | |
428 | cmdinfo->state &= ~SUBMIT_DATA_OUT_URB; | |
429 | } | |
430 | ||
431 | if (cmdinfo->state & ALLOC_CMD_URB) { | |
432 | cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd, | |
433 | cmdinfo->stream); | |
434 | if (!cmdinfo->cmd_urb) | |
435 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
436 | cmdinfo->state &= ~ALLOC_CMD_URB; | |
437 | } | |
438 | ||
439 | if (cmdinfo->state & SUBMIT_CMD_URB) { | |
440 | if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) { | |
441 | scmd_printk(KERN_INFO, cmnd, | |
442 | "cmd urb submission failure\n"); | |
443 | return SCSI_MLQUEUE_DEVICE_BUSY; | |
444 | } | |
445 | cmdinfo->state &= ~SUBMIT_CMD_URB; | |
446 | } | |
447 | ||
448 | return 0; | |
449 | } | |
450 | ||
f281233d | 451 | static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, |
115bb1ff MW |
452 | void (*done)(struct scsi_cmnd *)) |
453 | { | |
454 | struct scsi_device *sdev = cmnd->device; | |
455 | struct uas_dev_info *devinfo = sdev->hostdata; | |
456 | struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; | |
457 | int err; | |
458 | ||
459 | BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); | |
460 | ||
92a3f767 | 461 | if (!cmdinfo->status_urb && sdev->current_cmnd) |
115bb1ff MW |
462 | return SCSI_MLQUEUE_DEVICE_BUSY; |
463 | ||
464 | if (blk_rq_tagged(cmnd->request)) { | |
465 | cmdinfo->stream = cmnd->request->tag + 1; | |
466 | } else { | |
467 | sdev->current_cmnd = cmnd; | |
468 | cmdinfo->stream = 1; | |
469 | } | |
470 | ||
471 | cmnd->scsi_done = done; | |
472 | ||
92a3f767 | 473 | cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB | |
115bb1ff MW |
474 | ALLOC_CMD_URB | SUBMIT_CMD_URB; |
475 | ||
476 | switch (cmnd->sc_data_direction) { | |
477 | case DMA_FROM_DEVICE: | |
478 | cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; | |
479 | break; | |
480 | case DMA_BIDIRECTIONAL: | |
481 | cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; | |
482 | case DMA_TO_DEVICE: | |
483 | cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB; | |
484 | case DMA_NONE: | |
485 | break; | |
486 | } | |
487 | ||
488 | if (!devinfo->use_streams) { | |
489 | cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); | |
490 | cmdinfo->stream = 0; | |
491 | } | |
492 | ||
493 | err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); | |
494 | if (err) { | |
495 | /* If we did nothing, give up now */ | |
92a3f767 MW |
496 | if (cmdinfo->state & SUBMIT_STATUS_URB) { |
497 | usb_free_urb(cmdinfo->status_urb); | |
115bb1ff MW |
498 | return SCSI_MLQUEUE_DEVICE_BUSY; |
499 | } | |
500 | spin_lock(&uas_work_lock); | |
501 | list_add_tail(&cmdinfo->list, &uas_work_list); | |
502 | spin_unlock(&uas_work_lock); | |
503 | schedule_work(&uas_work); | |
504 | } | |
505 | ||
506 | return 0; | |
507 | } | |
508 | ||
f281233d JG |
509 | static DEF_SCSI_QCMD(uas_queuecommand) |
510 | ||
115bb1ff MW |
511 | static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) |
512 | { | |
513 | struct scsi_device *sdev = cmnd->device; | |
514 | sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, | |
515 | cmnd->request->tag); | |
516 | ||
517 | /* XXX: Send ABORT TASK Task Management command */ | |
518 | return FAILED; | |
519 | } | |
520 | ||
521 | static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) | |
522 | { | |
523 | struct scsi_device *sdev = cmnd->device; | |
524 | sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, | |
525 | cmnd->request->tag); | |
526 | ||
527 | /* XXX: Send LOGICAL UNIT RESET Task Management command */ | |
528 | return FAILED; | |
529 | } | |
530 | ||
531 | static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd) | |
532 | { | |
533 | struct scsi_device *sdev = cmnd->device; | |
534 | sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, | |
535 | cmnd->request->tag); | |
536 | ||
537 | /* XXX: Can we reset just the one USB interface? | |
538 | * Would calling usb_set_interface() have the right effect? | |
539 | */ | |
540 | return FAILED; | |
541 | } | |
542 | ||
543 | static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) | |
544 | { | |
545 | struct scsi_device *sdev = cmnd->device; | |
546 | struct uas_dev_info *devinfo = sdev->hostdata; | |
547 | struct usb_device *udev = devinfo->udev; | |
548 | ||
549 | sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, | |
550 | cmnd->request->tag); | |
551 | ||
552 | if (usb_reset_device(udev)) | |
553 | return SUCCESS; | |
554 | ||
555 | return FAILED; | |
556 | } | |
557 | ||
558 | static int uas_slave_alloc(struct scsi_device *sdev) | |
559 | { | |
560 | sdev->hostdata = (void *)sdev->host->hostdata[0]; | |
561 | return 0; | |
562 | } | |
563 | ||
564 | static int uas_slave_configure(struct scsi_device *sdev) | |
565 | { | |
566 | struct uas_dev_info *devinfo = sdev->hostdata; | |
567 | scsi_set_tag_type(sdev, MSG_ORDERED_TAG); | |
568 | scsi_activate_tcq(sdev, devinfo->qdepth - 1); | |
569 | return 0; | |
570 | } | |
571 | ||
572 | static struct scsi_host_template uas_host_template = { | |
573 | .module = THIS_MODULE, | |
574 | .name = "uas", | |
575 | .queuecommand = uas_queuecommand, | |
576 | .slave_alloc = uas_slave_alloc, | |
577 | .slave_configure = uas_slave_configure, | |
578 | .eh_abort_handler = uas_eh_abort_handler, | |
579 | .eh_device_reset_handler = uas_eh_device_reset_handler, | |
580 | .eh_target_reset_handler = uas_eh_target_reset_handler, | |
581 | .eh_bus_reset_handler = uas_eh_bus_reset_handler, | |
582 | .can_queue = 65536, /* Is there a limit on the _host_ ? */ | |
583 | .this_id = -1, | |
584 | .sg_tablesize = SG_NONE, | |
585 | .cmd_per_lun = 1, /* until we override it */ | |
586 | .skip_settle_delay = 1, | |
587 | .ordered_tag = 1, | |
588 | }; | |
589 | ||
590 | static struct usb_device_id uas_usb_ids[] = { | |
591 | { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) }, | |
592 | { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) }, | |
593 | /* 0xaa is a prototype device I happen to have access to */ | |
594 | { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, 0xaa) }, | |
595 | { } | |
596 | }; | |
597 | MODULE_DEVICE_TABLE(usb, uas_usb_ids); | |
598 | ||
89dc2905 MW |
599 | static int uas_is_interface(struct usb_host_interface *intf) |
600 | { | |
601 | return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE && | |
602 | intf->desc.bInterfaceSubClass == USB_SC_SCSI && | |
603 | intf->desc.bInterfaceProtocol == USB_PR_UAS); | |
604 | } | |
605 | ||
606 | static int uas_switch_interface(struct usb_device *udev, | |
607 | struct usb_interface *intf) | |
608 | { | |
609 | int i; | |
610 | ||
611 | if (uas_is_interface(intf->cur_altsetting)) | |
612 | return 0; | |
613 | ||
614 | for (i = 0; i < intf->num_altsetting; i++) { | |
615 | struct usb_host_interface *alt = &intf->altsetting[i]; | |
616 | if (alt == intf->cur_altsetting) | |
617 | continue; | |
618 | if (uas_is_interface(alt)) | |
619 | return usb_set_interface(udev, | |
620 | alt->desc.bInterfaceNumber, | |
621 | alt->desc.bAlternateSetting); | |
622 | } | |
623 | ||
624 | return -ENODEV; | |
625 | } | |
626 | ||
115bb1ff MW |
627 | static void uas_configure_endpoints(struct uas_dev_info *devinfo) |
628 | { | |
629 | struct usb_host_endpoint *eps[4] = { }; | |
630 | struct usb_interface *intf = devinfo->intf; | |
631 | struct usb_device *udev = devinfo->udev; | |
632 | struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint; | |
633 | unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; | |
634 | ||
635 | devinfo->uas_sense_old = 0; | |
636 | ||
637 | for (i = 0; i < n_endpoints; i++) { | |
638 | unsigned char *extra = endpoint[i].extra; | |
639 | int len = endpoint[i].extralen; | |
640 | while (len > 1) { | |
641 | if (extra[1] == USB_DT_PIPE_USAGE) { | |
642 | unsigned pipe_id = extra[2]; | |
643 | if (pipe_id > 0 && pipe_id < 5) | |
644 | eps[pipe_id - 1] = &endpoint[i]; | |
645 | break; | |
646 | } | |
647 | len -= extra[0]; | |
648 | extra += extra[0]; | |
649 | } | |
650 | } | |
651 | ||
652 | /* | |
653 | * Assume that if we didn't find a control pipe descriptor, we're | |
654 | * using a device with old firmware that happens to be set up like | |
655 | * this. | |
656 | */ | |
657 | if (!eps[0]) { | |
658 | devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1); | |
659 | devinfo->status_pipe = usb_rcvbulkpipe(udev, 1); | |
660 | devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2); | |
661 | devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2); | |
662 | ||
663 | eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe); | |
664 | eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); | |
665 | eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); | |
666 | } else { | |
667 | devinfo->cmd_pipe = usb_sndbulkpipe(udev, | |
668 | eps[0]->desc.bEndpointAddress); | |
669 | devinfo->status_pipe = usb_rcvbulkpipe(udev, | |
670 | eps[1]->desc.bEndpointAddress); | |
671 | devinfo->data_in_pipe = usb_rcvbulkpipe(udev, | |
672 | eps[2]->desc.bEndpointAddress); | |
673 | devinfo->data_out_pipe = usb_sndbulkpipe(udev, | |
674 | eps[3]->desc.bEndpointAddress); | |
675 | } | |
676 | ||
677 | devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256, | |
678 | GFP_KERNEL); | |
679 | if (devinfo->qdepth < 0) { | |
680 | devinfo->qdepth = 256; | |
681 | devinfo->use_streams = 0; | |
682 | } else { | |
683 | devinfo->use_streams = 1; | |
684 | } | |
685 | } | |
686 | ||
dae51546 SAS |
687 | static void uas_free_streams(struct uas_dev_info *devinfo) |
688 | { | |
689 | struct usb_device *udev = devinfo->udev; | |
690 | struct usb_host_endpoint *eps[3]; | |
691 | ||
692 | eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); | |
693 | eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); | |
694 | eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); | |
695 | usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL); | |
696 | } | |
697 | ||
115bb1ff MW |
698 | /* |
699 | * XXX: What I'd like to do here is register a SCSI host for each USB host in | |
700 | * the system. Follow usb-storage's design of registering a SCSI host for | |
701 | * each USB device for the moment. Can implement this by walking up the | |
702 | * USB hierarchy until we find a USB host. | |
703 | */ | |
704 | static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) | |
705 | { | |
706 | int result; | |
707 | struct Scsi_Host *shost; | |
708 | struct uas_dev_info *devinfo; | |
709 | struct usb_device *udev = interface_to_usbdev(intf); | |
710 | ||
89dc2905 MW |
711 | if (uas_switch_interface(udev, intf)) |
712 | return -ENODEV; | |
115bb1ff MW |
713 | |
714 | devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL); | |
715 | if (!devinfo) | |
716 | return -ENOMEM; | |
717 | ||
718 | result = -ENOMEM; | |
719 | shost = scsi_host_alloc(&uas_host_template, sizeof(void *)); | |
720 | if (!shost) | |
721 | goto free; | |
722 | ||
723 | shost->max_cmd_len = 16 + 252; | |
724 | shost->max_id = 1; | |
725 | shost->sg_tablesize = udev->bus->sg_tablesize; | |
726 | ||
115bb1ff MW |
727 | devinfo->intf = intf; |
728 | devinfo->udev = udev; | |
729 | uas_configure_endpoints(devinfo); | |
730 | ||
dae51546 SAS |
731 | result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 1); |
732 | if (result) | |
733 | goto free; | |
734 | ||
735 | result = scsi_add_host(shost, &intf->dev); | |
736 | if (result) | |
737 | goto deconfig_eps; | |
738 | ||
739 | shost->hostdata[0] = (unsigned long)devinfo; | |
740 | ||
115bb1ff MW |
741 | scsi_scan_host(shost); |
742 | usb_set_intfdata(intf, shost); | |
743 | return result; | |
dae51546 SAS |
744 | |
745 | deconfig_eps: | |
746 | uas_free_streams(devinfo); | |
115bb1ff MW |
747 | free: |
748 | kfree(devinfo); | |
749 | if (shost) | |
750 | scsi_host_put(shost); | |
751 | return result; | |
752 | } | |
753 | ||
754 | static int uas_pre_reset(struct usb_interface *intf) | |
755 | { | |
756 | /* XXX: Need to return 1 if it's not our device in error handling */ | |
757 | return 0; | |
758 | } | |
759 | ||
760 | static int uas_post_reset(struct usb_interface *intf) | |
761 | { | |
762 | /* XXX: Need to return 1 if it's not our device in error handling */ | |
763 | return 0; | |
764 | } | |
765 | ||
766 | static void uas_disconnect(struct usb_interface *intf) | |
767 | { | |
115bb1ff MW |
768 | struct Scsi_Host *shost = usb_get_intfdata(intf); |
769 | struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; | |
770 | ||
771 | scsi_remove_host(shost); | |
dae51546 | 772 | uas_free_streams(devinfo); |
115bb1ff MW |
773 | kfree(devinfo); |
774 | } | |
775 | ||
776 | /* | |
777 | * XXX: Should this plug into libusual so we can auto-upgrade devices from | |
778 | * Bulk-Only to UAS? | |
779 | */ | |
780 | static struct usb_driver uas_driver = { | |
781 | .name = "uas", | |
782 | .probe = uas_probe, | |
783 | .disconnect = uas_disconnect, | |
784 | .pre_reset = uas_pre_reset, | |
785 | .post_reset = uas_post_reset, | |
786 | .id_table = uas_usb_ids, | |
787 | }; | |
788 | ||
789 | static int uas_init(void) | |
790 | { | |
791 | return usb_register(&uas_driver); | |
792 | } | |
793 | ||
794 | static void uas_exit(void) | |
795 | { | |
796 | usb_deregister(&uas_driver); | |
797 | } | |
798 | ||
799 | module_init(uas_init); | |
800 | module_exit(uas_exit); | |
801 | ||
802 | MODULE_LICENSE("GPL"); | |
803 | MODULE_AUTHOR("Matthew Wilcox and Sarah Sharp"); |