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