aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-06-19 03:54:54 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-25 14:51:01 -0400
commit023b515e5b304122f3802abaa68d1da46fdf48b8 (patch)
treea56225ce211baf8216c24c2fc00f21c75266e419
parentbdd000fb34202530e5cd11260d06f57e2daf63c9 (diff)
uas: task mgmt & error handling
Add task management support, wind up in abort and device reset error handlers. Cancel all in-flight urbs in bus reset handler. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/storage/uas.c160
-rw-r--r--include/linux/usb/uas.h40
2 files changed, 171 insertions, 29 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 875829a56183..638cd64f9610 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -43,7 +43,8 @@ struct uas_dev_info {
43 struct usb_device *udev; 43 struct usb_device *udev;
44 struct usb_anchor sense_urbs; 44 struct usb_anchor sense_urbs;
45 struct usb_anchor data_urbs; 45 struct usb_anchor data_urbs;
46 int qdepth; 46 int qdepth, resetting;
47 struct response_ui response;
47 unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; 48 unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
48 unsigned use_streams:1; 49 unsigned use_streams:1;
49 unsigned uas_sense_old:1; 50 unsigned uas_sense_old:1;
@@ -68,6 +69,7 @@ enum {
68struct uas_cmd_info { 69struct uas_cmd_info {
69 unsigned int state; 70 unsigned int state;
70 unsigned int stream; 71 unsigned int stream;
72 unsigned int aborted;
71 struct urb *cmd_urb; 73 struct urb *cmd_urb;
72 struct urb *data_in_urb; 74 struct urb *data_in_urb;
73 struct urb *data_out_urb; 75 struct urb *data_out_urb;
@@ -222,16 +224,24 @@ static void uas_stat_cmplt(struct urb *urb)
222 return; 224 return;
223 } 225 }
224 226
227 if (devinfo->resetting) {
228 usb_free_urb(urb);
229 return;
230 }
231
225 tag = be16_to_cpup(&iu->tag) - 1; 232 tag = be16_to_cpup(&iu->tag) - 1;
226 if (tag == 0) 233 if (tag == 0)
227 cmnd = devinfo->cmnd; 234 cmnd = devinfo->cmnd;
228 else 235 else
229 cmnd = scsi_host_find_tag(shost, tag - 1); 236 cmnd = scsi_host_find_tag(shost, tag - 1);
230 if (!cmnd) { 237 if (!cmnd) {
231 usb_free_urb(urb); 238 if (iu->iu_id != IU_ID_RESPONSE) {
232 return; 239 usb_free_urb(urb);
240 return;
241 }
242 } else {
243 cmdinfo = (void *)&cmnd->SCp;
233 } 244 }
234 cmdinfo = (void *)&cmnd->SCp;
235 245
236 switch (iu->iu_id) { 246 switch (iu->iu_id) {
237 case IU_ID_STATUS: 247 case IU_ID_STATUS:
@@ -260,6 +270,10 @@ static void uas_stat_cmplt(struct urb *urb)
260 case IU_ID_WRITE_READY: 270 case IU_ID_WRITE_READY:
261 uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB); 271 uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
262 break; 272 break;
273 case IU_ID_RESPONSE:
274 /* store results for uas_eh_task_mgmt() */
275 memcpy(&devinfo->response, iu, sizeof(devinfo->response));
276 break;
263 default: 277 default:
264 scmd_printk(KERN_ERR, cmnd, 278 scmd_printk(KERN_ERR, cmnd,
265 "Bogus IU (%d) received on status pipe\n", iu->iu_id); 279 "Bogus IU (%d) received on status pipe\n", iu->iu_id);
@@ -287,6 +301,9 @@ static void uas_data_cmplt(struct urb *urb)
287 } else { 301 } else {
288 sdb->resid = sdb->length - urb->actual_length; 302 sdb->resid = sdb->length - urb->actual_length;
289 } 303 }
304 if (cmdinfo->aborted) {
305 return;
306 }
290 uas_try_complete(cmnd, __func__); 307 uas_try_complete(cmnd, __func__);
291} 308}
292 309
@@ -377,6 +394,51 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
377 return NULL; 394 return NULL;
378} 395}
379 396
397static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
398 u8 function, u16 stream_id)
399{
400 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
401 struct usb_device *udev = devinfo->udev;
402 struct urb *urb = usb_alloc_urb(0, gfp);
403 struct task_mgmt_iu *iu;
404 int err = -ENOMEM;
405
406 if (!urb)
407 goto err;
408
409 iu = kzalloc(sizeof(*iu), gfp);
410 if (!iu)
411 goto err;
412
413 iu->iu_id = IU_ID_TASK_MGMT;
414 iu->tag = cpu_to_be16(stream_id);
415 int_to_scsilun(cmnd->device->lun, &iu->lun);
416
417 iu->function = function;
418 switch (function) {
419 case TMF_ABORT_TASK:
420 if (blk_rq_tagged(cmnd->request))
421 iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
422 else
423 iu->task_tag = cpu_to_be16(1);
424 break;
425 }
426
427 usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
428 usb_free_urb, NULL);
429 urb->transfer_flags |= URB_FREE_BUFFER;
430
431 err = usb_submit_urb(urb, gfp);
432 if (err)
433 goto err;
434
435 return 0;
436
437err:
438 usb_free_urb(urb);
439 return err;
440}
441
380/* 442/*
381 * Why should I request the Status IU before sending the Command IU? Spec 443 * Why should I request the Status IU before sending the Command IU? Spec
382 * says to, but also says the device may receive them in any order. Seems 444 * says to, but also says the device may receive them in any order. Seems
@@ -502,6 +564,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
502 564
503 cmdinfo->state = SUBMIT_STATUS_URB | 565 cmdinfo->state = SUBMIT_STATUS_URB |
504 ALLOC_CMD_URB | SUBMIT_CMD_URB; 566 ALLOC_CMD_URB | SUBMIT_CMD_URB;
567 cmdinfo->aborted = 0;
505 568
506 switch (cmnd->sc_data_direction) { 569 switch (cmnd->sc_data_direction) {
507 case DMA_FROM_DEVICE: 570 case DMA_FROM_DEVICE:
@@ -537,34 +600,66 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
537 600
538static DEF_SCSI_QCMD(uas_queuecommand) 601static DEF_SCSI_QCMD(uas_queuecommand)
539 602
540static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) 603static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
604 const char *fname, u8 function)
541{ 605{
542 uas_log_cmd_state(cmnd, __func__); 606 struct Scsi_Host *shost = cmnd->device->host;
607 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
608 u16 tag = 9999; /* FIXME */
543 609
544/* XXX: Send ABORT TASK Task Management command */ 610 memset(&devinfo->response, 0, sizeof(devinfo->response));
545 return FAILED; 611 if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) {
612 shost_printk(KERN_INFO, shost,
613 "%s: %s: submit sense urb failed\n",
614 __func__, fname);
615 return FAILED;
616 }
617 if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
618 shost_printk(KERN_INFO, shost,
619 "%s: %s: submit task mgmt urb failed\n",
620 __func__, fname);
621 return FAILED;
622 }
623 if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) {
624 shost_printk(KERN_INFO, shost,
625 "%s: %s timed out\n", __func__, fname);
626 return FAILED;
627 }
628 if (be16_to_cpu(devinfo->response.tag) != tag) {
629 shost_printk(KERN_INFO, shost,
630 "%s: %s failed (wrong tag %d/%d)\n", __func__,
631 fname, be16_to_cpu(devinfo->response.tag), tag);
632 return FAILED;
633 }
634 if (devinfo->response.response_code != RC_TMF_COMPLETE) {
635 shost_printk(KERN_INFO, shost,
636 "%s: %s failed (rc 0x%x)\n", __func__,
637 fname, devinfo->response.response_code);
638 return FAILED;
639 }
640 return SUCCESS;
546} 641}
547 642
548static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) 643static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
549{ 644{
550 struct scsi_device *sdev = cmnd->device; 645 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
551 sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, 646 int ret;
552 cmnd->request->tag);
553 647
554/* XXX: Send LOGICAL UNIT RESET Task Management command */ 648 uas_log_cmd_state(cmnd, __func__);
555 return FAILED; 649 cmdinfo->aborted = 1;
650 ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
651 if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
652 usb_kill_urb(cmdinfo->data_in_urb);
653 if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
654 usb_kill_urb(cmdinfo->data_out_urb);
655 return ret;
556} 656}
557 657
558static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd) 658static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
559{ 659{
560 struct scsi_device *sdev = cmnd->device; 660 sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
561 sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, 661 return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
562 cmnd->request->tag); 662 TMF_LOGICAL_UNIT_RESET);
563
564/* XXX: Can we reset just the one USB interface?
565 * Would calling usb_set_interface() have the right effect?
566 */
567 return FAILED;
568} 663}
569 664
570static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) 665static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
@@ -572,14 +667,21 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
572 struct scsi_device *sdev = cmnd->device; 667 struct scsi_device *sdev = cmnd->device;
573 struct uas_dev_info *devinfo = sdev->hostdata; 668 struct uas_dev_info *devinfo = sdev->hostdata;
574 struct usb_device *udev = devinfo->udev; 669 struct usb_device *udev = devinfo->udev;
670 int err;
575 671
576 sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, 672 devinfo->resetting = 1;
577 cmnd->request->tag); 673 usb_kill_anchored_urbs(&devinfo->sense_urbs);
674 usb_kill_anchored_urbs(&devinfo->data_urbs);
675 err = usb_reset_device(udev);
676 devinfo->resetting = 0;
578 677
579 if (usb_reset_device(udev)) 678 if (err) {
580 return SUCCESS; 679 shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
680 return FAILED;
681 }
581 682
582 return FAILED; 683 shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
684 return SUCCESS;
583} 685}
584 686
585static int uas_slave_alloc(struct scsi_device *sdev) 687static int uas_slave_alloc(struct scsi_device *sdev)
@@ -604,7 +706,6 @@ static struct scsi_host_template uas_host_template = {
604 .slave_configure = uas_slave_configure, 706 .slave_configure = uas_slave_configure,
605 .eh_abort_handler = uas_eh_abort_handler, 707 .eh_abort_handler = uas_eh_abort_handler,
606 .eh_device_reset_handler = uas_eh_device_reset_handler, 708 .eh_device_reset_handler = uas_eh_device_reset_handler,
607 .eh_target_reset_handler = uas_eh_target_reset_handler,
608 .eh_bus_reset_handler = uas_eh_bus_reset_handler, 709 .eh_bus_reset_handler = uas_eh_bus_reset_handler,
609 .can_queue = 65536, /* Is there a limit on the _host_ ? */ 710 .can_queue = 65536, /* Is there a limit on the _host_ ? */
610 .this_id = -1, 711 .this_id = -1,
@@ -766,6 +867,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
766 867
767 devinfo->intf = intf; 868 devinfo->intf = intf;
768 devinfo->udev = udev; 869 devinfo->udev = udev;
870 devinfo->resetting = 0;
769 init_usb_anchor(&devinfo->sense_urbs); 871 init_usb_anchor(&devinfo->sense_urbs);
770 init_usb_anchor(&devinfo->data_urbs); 872 init_usb_anchor(&devinfo->data_urbs);
771 uas_configure_endpoints(devinfo); 873 uas_configure_endpoints(devinfo);
diff --git a/include/linux/usb/uas.h b/include/linux/usb/uas.h
index 9a988e413694..5499ab5c94bd 100644
--- a/include/linux/usb/uas.h
+++ b/include/linux/usb/uas.h
@@ -20,6 +20,28 @@ enum {
20 IU_ID_WRITE_READY = 0x07, 20 IU_ID_WRITE_READY = 0x07,
21}; 21};
22 22
23enum {
24 TMF_ABORT_TASK = 0x01,
25 TMF_ABORT_TASK_SET = 0x02,
26 TMF_CLEAR_TASK_SET = 0x04,
27 TMF_LOGICAL_UNIT_RESET = 0x08,
28 TMF_I_T_NEXUS_RESET = 0x10,
29 TMF_CLEAR_ACA = 0x40,
30 TMF_QUERY_TASK = 0x80,
31 TMF_QUERY_TASK_SET = 0x81,
32 TMF_QUERY_ASYNC_EVENT = 0x82,
33};
34
35enum {
36 RC_TMF_COMPLETE = 0x00,
37 RC_INVALID_INFO_UNIT = 0x02,
38 RC_TMF_NOT_SUPPORTED = 0x04,
39 RC_TMF_FAILED = 0x05,
40 RC_TMF_SUCCEEDED = 0x08,
41 RC_INCORRECT_LUN = 0x09,
42 RC_OVERLAPPED_TAG = 0x0a,
43};
44
23struct command_iu { 45struct command_iu {
24 __u8 iu_id; 46 __u8 iu_id;
25 __u8 rsvd1; 47 __u8 rsvd1;
@@ -32,6 +54,16 @@ struct command_iu {
32 __u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */ 54 __u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
33}; 55};
34 56
57struct task_mgmt_iu {
58 __u8 iu_id;
59 __u8 rsvd1;
60 __be16 tag;
61 __u8 function;
62 __u8 rsvd2;
63 __be16 task_tag;
64 struct scsi_lun lun;
65};
66
35/* 67/*
36 * Also used for the Read Ready and Write Ready IUs since they have the 68 * Also used for the Read Ready and Write Ready IUs since they have the
37 * same first four bytes 69 * same first four bytes
@@ -47,6 +79,14 @@ struct sense_iu {
47 __u8 sense[SCSI_SENSE_BUFFERSIZE]; 79 __u8 sense[SCSI_SENSE_BUFFERSIZE];
48}; 80};
49 81
82struct response_ui {
83 __u8 iu_id;
84 __u8 rsvd1;
85 __be16 tag;
86 __be16 add_response_info;
87 __u8 response_code;
88};
89
50struct usb_pipe_usage_descriptor { 90struct usb_pipe_usage_descriptor {
51 __u8 bLength; 91 __u8 bLength;
52 __u8 bDescriptorType; 92 __u8 bDescriptorType;