[PATCH 12/14] uas: handle response to LUN reset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Simple evaluation of the response uis result codes

Signed-off-by: Oliver Neukum <oneukum@xxxxxxxx>
---
 drivers/usb/storage/uas.c | 80 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 65 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 843c73e..d2d9244 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -57,7 +57,7 @@ struct uas_dev_info {
 	spinlock_t lock;
 	struct work_struct work;
 	struct completion deathknell;
-	bool aborted; /* a reply to a TASK ABORT was seen */
+	bool tmf_perfomed; /* an ack to a TMF was seen */
 	bool tmf_catastrophic; /* TMF failed, retry useless */
 	bool tmf_error; /* tmf may be retried after error handling */
 };
@@ -271,9 +271,9 @@ static void finish_tmf(struct uas_dev_info *devinfo, struct response_iu *riu, st
 	uas_log_cmd_state(cmnd, "expected response iu", response_code);
 
 	if (response_code == RC_TMF_SUCCEEDED)
-		devinfo->aborted = true;
+		devinfo->tmf_perfomed = true;
 	else
-		devinfo->aborted = false;
+		devinfo->tmf_perfomed = false;
 }
 
 static bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd *cmnd)
@@ -796,6 +796,35 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 
 static DEF_SCSI_QCMD(uas_queuecommand)
 
+static void prepare_tmf_urb(struct uas_dev_info *devinfo, struct scsi_cmnd *cmnd)
+{
+	usb_fill_bulk_urb(devinfo->management_urb,
+			  devinfo->udev,
+			  devinfo->cmd_pipe, /* shared */
+			  devinfo->tmf_iu,
+			  sizeof(devinfo->tmf_iu),
+			  uas_tmf_cmplt,
+			  cmnd->device->host);
+}
+
+static void prepare_ABORT_TASK_tmf(struct task_mgmt_iu *tmf, struct uas_cmd_info *cmdinfo)
+{
+	memset(tmf, 0, sizeof(struct task_mgmt_iu));
+	tmf->iu_id = IU_ID_TASK_MGMT;
+	tmf->tag = cpu_to_be16( TAG_FOR_TMF );
+	tmf->function = TMF_ABORT_TASK;
+	tmf->task_tag = cmdinfo->uas_tag; /* already BE */
+}
+
+static void prepare_LOGICAL_UNIT_RESET_tmf(struct task_mgmt_iu *tmf, struct scsi_device *sdev)
+{
+	memset(tmf, 0, sizeof(struct task_mgmt_iu));
+	tmf->iu_id = IU_ID_TASK_MGMT;
+	tmf->tag = cpu_to_be16( TAG_FOR_TMF );
+	tmf->function = TMF_LOGICAL_UNIT_RESET;
+	int_to_scsilun(sdev->lun, &tmf->lun);
+}
+
 /*
  * For now we do not support actually sending an abort to the device, so
  * this eh always fails. Still we must define it to make sure that we've
@@ -823,17 +852,9 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 	devinfo->deathrow = cmnd;
 	devinfo->tmf_catastrophic = false;
 	devinfo->tmf_error = false;
-	usb_fill_bulk_urb(devinfo->management_urb,
-			  devinfo->udev,
-			  devinfo->cmd_pipe, /* shared */
-			  devinfo->tmf_iu,
-			  sizeof(devinfo->tmf_iu),
-			  uas_tmf_cmplt,
-			  cmnd->device->host);
-	tmf->iu_id = IU_ID_TASK_MGMT;
-	tmf->tag = cpu_to_be16( TAG_FOR_TMF );
-	tmf->function = TMF_ABORT_TASK;
-	tmf->task_tag = cmdinfo->uas_tag; /* already BE */
+
+	prepare_tmf_urb(devinfo, cmnd);
+	prepare_ABORT_TASK_tmf(tmf, cmdinfo);
 
 	err = usb_submit_urb(devinfo->management_urb, GFP_NOIO);
 	if (err < 0) /* unkillable */
@@ -848,7 +869,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 	time = wait_for_completion_timeout(&devinfo->deathknell, USB_CTRL_GET_TIMEOUT);
 	/* in case of timeout */
 	usb_kill_urb(devinfo->management_urb);
-	if (time && devinfo->aborted) {
+	if (time && devinfo->tmf_perfomed) {
 		cmdinfo->state &= ~COMMAND_ABORTING;
 		/*
 		 * manually finish as resources must be freed only once
@@ -886,6 +907,34 @@ give_up:
 	return success;
 }
 
+static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
+{
+	struct scsi_device *sdev = cmnd->device;
+	struct uas_dev_info *devinfo = sdev->hostdata;
+	struct task_mgmt_iu *tmf = devinfo->tmf_iu;
+	int success = FAILED;
+	int err;
+	int time;
+
+	devinfo->tmf_catastrophic = false;
+	devinfo->tmf_error = false;
+	init_completion(&devinfo->deathknell);
+	prepare_tmf_urb(devinfo, cmnd);
+	prepare_LOGICAL_UNIT_RESET_tmf(tmf, cmnd->device);
+
+	err = usb_submit_urb(devinfo->management_urb, GFP_NOIO);
+	if (err < 0)
+		goto failure;
+
+	time = wait_for_completion_timeout(&devinfo->deathknell, USB_CTRL_GET_TIMEOUT);
+	if (time && devinfo->tmf_perfomed)
+		success = SUCCESS;
+	usb_kill_urb(devinfo->management_urb);
+
+failure:
+	return success;
+}
+
 static int uas_eh_host_reset_handler(struct scsi_cmnd *cmnd)
 {
 	struct scsi_device *sdev = cmnd->device;
@@ -990,6 +1039,7 @@ static struct scsi_host_template uas_host_template = {
 	.slave_alloc = uas_slave_alloc,
 	.slave_configure = uas_slave_configure,
 	.eh_abort_handler = uas_eh_abort_handler,
+	.eh_device_reset_handler = uas_eh_device_reset_handler,
 	.eh_host_reset_handler = uas_eh_host_reset_handler,
 	.can_queue = 65536,	/* Is there a limit on the _host_ ? */
 	.this_id = -1,
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux