Skip to content

Commit 023b515

Browse files
kraxelgregkh
authored andcommitted
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>
1 parent bdd000f commit 023b515

File tree

2 files changed

+171
-29
lines changed

2 files changed

+171
-29
lines changed

drivers/usb/storage/uas.c

Lines changed: 131 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ struct uas_dev_info {
4343
struct usb_device *udev;
4444
struct usb_anchor sense_urbs;
4545
struct usb_anchor data_urbs;
46-
int qdepth;
46+
int qdepth, resetting;
47+
struct response_ui response;
4748
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
4849
unsigned use_streams:1;
4950
unsigned uas_sense_old:1;
@@ -68,6 +69,7 @@ enum {
6869
struct uas_cmd_info {
6970
unsigned int state;
7071
unsigned int stream;
72+
unsigned int aborted;
7173
struct urb *cmd_urb;
7274
struct urb *data_in_urb;
7375
struct urb *data_out_urb;
@@ -222,16 +224,24 @@ static void uas_stat_cmplt(struct urb *urb)
222224
return;
223225
}
224226

227+
if (devinfo->resetting) {
228+
usb_free_urb(urb);
229+
return;
230+
}
231+
225232
tag = be16_to_cpup(&iu->tag) - 1;
226233
if (tag == 0)
227234
cmnd = devinfo->cmnd;
228235
else
229236
cmnd = scsi_host_find_tag(shost, tag - 1);
230237
if (!cmnd) {
231-
usb_free_urb(urb);
232-
return;
238+
if (iu->iu_id != IU_ID_RESPONSE) {
239+
usb_free_urb(urb);
240+
return;
241+
}
242+
} else {
243+
cmdinfo = (void *)&cmnd->SCp;
233244
}
234-
cmdinfo = (void *)&cmnd->SCp;
235245

236246
switch (iu->iu_id) {
237247
case IU_ID_STATUS:
@@ -260,6 +270,10 @@ static void uas_stat_cmplt(struct urb *urb)
260270
case IU_ID_WRITE_READY:
261271
uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
262272
break;
273+
case IU_ID_RESPONSE:
274+
/* store results for uas_eh_task_mgmt() */
275+
memcpy(&devinfo->response, iu, sizeof(devinfo->response));
276+
break;
263277
default:
264278
scmd_printk(KERN_ERR, cmnd,
265279
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
@@ -287,6 +301,9 @@ static void uas_data_cmplt(struct urb *urb)
287301
} else {
288302
sdb->resid = sdb->length - urb->actual_length;
289303
}
304+
if (cmdinfo->aborted) {
305+
return;
306+
}
290307
uas_try_complete(cmnd, __func__);
291308
}
292309

@@ -377,6 +394,51 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
377394
return NULL;
378395
}
379396

397+
static 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+
437+
err:
438+
usb_free_urb(urb);
439+
return err;
440+
}
441+
380442
/*
381443
* Why should I request the Status IU before sending the Command IU? Spec
382444
* 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,
502564

503565
cmdinfo->state = SUBMIT_STATUS_URB |
504566
ALLOC_CMD_URB | SUBMIT_CMD_URB;
567+
cmdinfo->aborted = 0;
505568

506569
switch (cmnd->sc_data_direction) {
507570
case DMA_FROM_DEVICE:
@@ -537,49 +600,88 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
537600

538601
static DEF_SCSI_QCMD(uas_queuecommand)
539602

540-
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
603+
static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
604+
const char *fname, u8 function)
541605
{
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 */
543609

544-
/* XXX: Send ABORT TASK Task Management command */
545-
return FAILED;
610+
memset(&devinfo->response, 0, sizeof(devinfo->response));
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;
546641
}
547642

548-
static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
643+
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
549644
{
550-
struct scsi_device *sdev = cmnd->device;
551-
sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
552-
cmnd->request->tag);
645+
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
646+
int ret;
553647

554-
/* XXX: Send LOGICAL UNIT RESET Task Management command */
555-
return FAILED;
648+
uas_log_cmd_state(cmnd, __func__);
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;
556656
}
557657

558-
static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd)
658+
static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
559659
{
560-
struct scsi_device *sdev = cmnd->device;
561-
sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
562-
cmnd->request->tag);
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;
660+
sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
661+
return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
662+
TMF_LOGICAL_UNIT_RESET);
568663
}
569664

570665
static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
571666
{
572667
struct scsi_device *sdev = cmnd->device;
573668
struct uas_dev_info *devinfo = sdev->hostdata;
574669
struct usb_device *udev = devinfo->udev;
670+
int err;
575671

576-
sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
577-
cmnd->request->tag);
672+
devinfo->resetting = 1;
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;
578677

579-
if (usb_reset_device(udev))
580-
return SUCCESS;
678+
if (err) {
679+
shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
680+
return FAILED;
681+
}
581682

582-
return FAILED;
683+
shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
684+
return SUCCESS;
583685
}
584686

585687
static int uas_slave_alloc(struct scsi_device *sdev)
@@ -604,7 +706,6 @@ static struct scsi_host_template uas_host_template = {
604706
.slave_configure = uas_slave_configure,
605707
.eh_abort_handler = uas_eh_abort_handler,
606708
.eh_device_reset_handler = uas_eh_device_reset_handler,
607-
.eh_target_reset_handler = uas_eh_target_reset_handler,
608709
.eh_bus_reset_handler = uas_eh_bus_reset_handler,
609710
.can_queue = 65536, /* Is there a limit on the _host_ ? */
610711
.this_id = -1,
@@ -766,6 +867,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
766867

767868
devinfo->intf = intf;
768869
devinfo->udev = udev;
870+
devinfo->resetting = 0;
769871
init_usb_anchor(&devinfo->sense_urbs);
770872
init_usb_anchor(&devinfo->data_urbs);
771873
uas_configure_endpoints(devinfo);

include/linux/usb/uas.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,28 @@ enum {
2020
IU_ID_WRITE_READY = 0x07,
2121
};
2222

23+
enum {
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+
35+
enum {
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+
2345
struct command_iu {
2446
__u8 iu_id;
2547
__u8 rsvd1;
@@ -32,6 +54,16 @@ struct command_iu {
3254
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
3355
};
3456

57+
struct 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+
3567
/*
3668
* Also used for the Read Ready and Write Ready IUs since they have the
3769
* same first four bytes
@@ -47,6 +79,14 @@ struct sense_iu {
4779
__u8 sense[SCSI_SENSE_BUFFERSIZE];
4880
};
4981

82+
struct response_ui {
83+
__u8 iu_id;
84+
__u8 rsvd1;
85+
__be16 tag;
86+
__be16 add_response_info;
87+
__u8 response_code;
88+
};
89+
5090
struct usb_pipe_usage_descriptor {
5191
__u8 bLength;
5292
__u8 bDescriptorType;

0 commit comments

Comments
 (0)