diff options
Diffstat (limited to 'drivers/usb/storage/uas.c')
| -rw-r--r-- | drivers/usb/storage/uas.c | 420 | 
1 files changed, 248 insertions, 172 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 8ec8a6e66f5..638cd64f961 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -41,16 +41,17 @@ struct sense_iu_old {  struct uas_dev_info {  	struct usb_interface *intf;  	struct usb_device *udev; -	int qdepth; +	struct usb_anchor sense_urbs; +	struct usb_anchor data_urbs; +	int qdepth, resetting; +	struct response_ui response;  	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;  	unsigned use_streams:1;  	unsigned uas_sense_old:1;  	struct scsi_cmnd *cmnd; -	struct urb *status_urb; /* used only if stream support is available */  };  enum { -	ALLOC_STATUS_URB	= (1 << 0),  	SUBMIT_STATUS_URB	= (1 << 1),  	ALLOC_DATA_IN_URB	= (1 << 2),  	SUBMIT_DATA_IN_URB	= (1 << 3), @@ -58,18 +59,18 @@ enum {  	SUBMIT_DATA_OUT_URB	= (1 << 5),  	ALLOC_CMD_URB		= (1 << 6),  	SUBMIT_CMD_URB		= (1 << 7), -	COMPLETED_DATA_IN	= (1 << 8), -	COMPLETED_DATA_OUT	= (1 << 9), -	DATA_COMPLETES_CMD	= (1 << 10), +	COMMAND_INFLIGHT        = (1 << 8), +	DATA_IN_URB_INFLIGHT    = (1 << 9), +	DATA_OUT_URB_INFLIGHT   = (1 << 10), +	COMMAND_COMPLETED       = (1 << 11),  };  /* Overrides scsi_pointer */  struct uas_cmd_info {  	unsigned int state;  	unsigned int stream; +	unsigned int aborted;  	struct urb *cmd_urb; -	/* status_urb is used only if stream support isn't available */ -	struct urb *status_urb;  	struct urb *data_in_urb;  	struct urb *data_out_urb;  	struct list_head list; @@ -114,7 +115,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)  {  	struct sense_iu *sense_iu = urb->transfer_buffer;  	struct scsi_device *sdev = cmnd->device; -	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;  	if (urb->actual_length > 16) {  		unsigned len = be16_to_cpup(&sense_iu->len); @@ -132,15 +132,12 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)  	}  	cmnd->result = sense_iu->status; -	if (!(cmdinfo->state & DATA_COMPLETES_CMD)) -		cmnd->scsi_done(cmnd);  }  static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)  {  	struct sense_iu_old *sense_iu = urb->transfer_buffer;  	struct scsi_device *sdev = cmnd->device; -	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;  	if (urb->actual_length > 8) {  		unsigned len = be16_to_cpup(&sense_iu->len) - 2; @@ -158,17 +155,51 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)  	}  	cmnd->result = sense_iu->status; -	if (!(cmdinfo->state & DATA_COMPLETES_CMD)) -		cmnd->scsi_done(cmnd); +} + +static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller) +{ +	struct uas_cmd_info *ci = (void *)&cmnd->SCp; + +	scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:" +		    "%s%s%s%s%s%s%s%s%s%s%s\n", +		    caller, cmnd, cmnd->request->tag, +		    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "", +		    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "", +		    (ci->state & SUBMIT_DATA_IN_URB)    ? " s-in"  : "", +		    (ci->state & ALLOC_DATA_OUT_URB)    ? " a-out" : "", +		    (ci->state & SUBMIT_DATA_OUT_URB)   ? " s-out" : "", +		    (ci->state & ALLOC_CMD_URB)         ? " a-cmd" : "", +		    (ci->state & SUBMIT_CMD_URB)        ? " s-cmd" : "", +		    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "", +		    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "", +		    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "", +		    (ci->state & COMMAND_COMPLETED)     ? " done"  : ""); +} + +static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) +{ +	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; + +	if (cmdinfo->state & (COMMAND_INFLIGHT | +			      DATA_IN_URB_INFLIGHT | +			      DATA_OUT_URB_INFLIGHT)) +		return -EBUSY; +	BUG_ON(cmdinfo->state & COMMAND_COMPLETED); +	cmdinfo->state |= COMMAND_COMPLETED; +	usb_free_urb(cmdinfo->data_in_urb); +	usb_free_urb(cmdinfo->data_out_urb); +	cmnd->scsi_done(cmnd); +	return 0;  }  static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, -							unsigned direction) +			  unsigned direction)  {  	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;  	int err; -	cmdinfo->state = direction; +	cmdinfo->state |= direction | SUBMIT_STATUS_URB;  	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);  	if (err) {  		spin_lock(&uas_work_lock); @@ -186,12 +217,15 @@ static void uas_stat_cmplt(struct urb *urb)  	struct scsi_cmnd *cmnd;  	struct uas_cmd_info *cmdinfo;  	u16 tag; -	int ret;  	if (urb->status) {  		dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); -		if (devinfo->use_streams) -			usb_free_urb(urb); +		usb_free_urb(urb); +		return; +	} + +	if (devinfo->resetting) { +		usb_free_urb(urb);  		return;  	} @@ -201,47 +235,34 @@ static void uas_stat_cmplt(struct urb *urb)  	else  		cmnd = scsi_host_find_tag(shost, tag - 1);  	if (!cmnd) { -		if (devinfo->use_streams) { +		if (iu->iu_id != IU_ID_RESPONSE) {  			usb_free_urb(urb);  			return;  		} -		ret = usb_submit_urb(urb, GFP_ATOMIC); -		if (ret) -			dev_err(&urb->dev->dev, "failed submit status urb\n"); -		return; +	} else { +		cmdinfo = (void *)&cmnd->SCp;  	} -	cmdinfo = (void *)&cmnd->SCp;  	switch (iu->iu_id) {  	case IU_ID_STATUS:  		if (devinfo->cmnd == cmnd)  			devinfo->cmnd = NULL; -		if (!(cmdinfo->state & COMPLETED_DATA_IN) && -				cmdinfo->data_in_urb) { -		       if (devinfo->use_streams) { -			       cmdinfo->state |= DATA_COMPLETES_CMD; -			       usb_unlink_urb(cmdinfo->data_in_urb); -		       } else { -			       usb_free_urb(cmdinfo->data_in_urb); -		       } -		} -		if (!(cmdinfo->state & COMPLETED_DATA_OUT) && -				cmdinfo->data_out_urb) { -			if (devinfo->use_streams) { -				cmdinfo->state |= DATA_COMPLETES_CMD; -				usb_unlink_urb(cmdinfo->data_in_urb); -			} else { -				usb_free_urb(cmdinfo->data_out_urb); -			} -		} -  		if (urb->actual_length < 16)  			devinfo->uas_sense_old = 1;  		if (devinfo->uas_sense_old)  			uas_sense_old(urb, cmnd);  		else  			uas_sense(urb, cmnd); +		if (cmnd->result != 0) { +			/* cancel data transfers on error */ +			if (cmdinfo->state & DATA_IN_URB_INFLIGHT) +				usb_unlink_urb(cmdinfo->data_in_urb); +			if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) +				usb_unlink_urb(cmdinfo->data_out_urb); +		} +		cmdinfo->state &= ~COMMAND_INFLIGHT; +		uas_try_complete(cmnd, __func__);  		break;  	case IU_ID_READ_READY:  		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB); @@ -249,74 +270,59 @@ static void uas_stat_cmplt(struct urb *urb)  	case IU_ID_WRITE_READY:  		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);  		break; +	case IU_ID_RESPONSE: +		/* store results for uas_eh_task_mgmt() */ +		memcpy(&devinfo->response, iu, sizeof(devinfo->response)); +		break;  	default:  		scmd_printk(KERN_ERR, cmnd,  			"Bogus IU (%d) received on status pipe\n", iu->iu_id);  	} - -	if (devinfo->use_streams) { -		usb_free_urb(urb); -		return; -	} - -	ret = usb_submit_urb(urb, GFP_ATOMIC); -	if (ret) -		dev_err(&urb->dev->dev, "failed submit status urb\n"); -} - -static void uas_data_out_cmplt(struct urb *urb) -{ -	struct scsi_cmnd *cmnd = urb->context; -	struct scsi_data_buffer *sdb = scsi_out(cmnd); -	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - -	cmdinfo->state |= COMPLETED_DATA_OUT; - -	sdb->resid = sdb->length - urb->actual_length;  	usb_free_urb(urb); - -	if (cmdinfo->state & DATA_COMPLETES_CMD) -		cmnd->scsi_done(cmnd);  } -static void uas_data_in_cmplt(struct urb *urb) +static void uas_data_cmplt(struct urb *urb)  {  	struct scsi_cmnd *cmnd = urb->context; -	struct scsi_data_buffer *sdb = scsi_in(cmnd);  	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; +	struct scsi_data_buffer *sdb = NULL; -	cmdinfo->state |= COMPLETED_DATA_IN; - -	sdb->resid = sdb->length - urb->actual_length; -	usb_free_urb(urb); - -	if (cmdinfo->state & DATA_COMPLETES_CMD) -		cmnd->scsi_done(cmnd); +	if (cmdinfo->data_in_urb == urb) { +		sdb = scsi_in(cmnd); +		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT; +	} else if (cmdinfo->data_out_urb == urb) { +		sdb = scsi_out(cmnd); +		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT; +	} +	BUG_ON(sdb == NULL); +	if (urb->status) { +		/* error: no data transfered */ +		sdb->resid = sdb->length; +	} else { +		sdb->resid = sdb->length - urb->actual_length; +	} +	if (cmdinfo->aborted) { +		return; +	} +	uas_try_complete(cmnd, __func__);  }  static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, -		unsigned int pipe, struct scsi_cmnd *cmnd, -		enum dma_data_direction dir) +				      unsigned int pipe, u16 stream_id, +				      struct scsi_cmnd *cmnd, +				      enum dma_data_direction dir)  { -	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;  	struct usb_device *udev = devinfo->udev;  	struct urb *urb = usb_alloc_urb(0, gfp); -	struct scsi_data_buffer *sdb; -	usb_complete_t complete_fn; -	u16 stream_id = cmdinfo->stream; +	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE) +		? scsi_in(cmnd) : scsi_out(cmnd);  	if (!urb)  		goto out; -	if (dir == DMA_FROM_DEVICE) { -		sdb = scsi_in(cmnd); -		complete_fn = uas_data_in_cmplt; -	} else { -		sdb = scsi_out(cmnd); -		complete_fn = uas_data_out_cmplt; -	}  	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, -			complete_fn, cmnd); -	urb->stream_id = stream_id; +			  uas_data_cmplt, cmnd); +	if (devinfo->use_streams) +		urb->stream_id = stream_id;  	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;  	urb->sg = sdb->table.sgl;   out: @@ -324,7 +330,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,  }  static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, -		struct Scsi_Host *shost, u16 stream_id) +				       struct Scsi_Host *shost, u16 stream_id)  {  	struct usb_device *udev = devinfo->udev;  	struct urb *urb = usb_alloc_urb(0, gfp); @@ -388,38 +394,95 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,  	return NULL;  } +static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp, +			       u8 function, u16 stream_id) +{ +	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; +	struct usb_device *udev = devinfo->udev; +	struct urb *urb = usb_alloc_urb(0, gfp); +	struct task_mgmt_iu *iu; +	int err = -ENOMEM; + +	if (!urb) +		goto err; + +	iu = kzalloc(sizeof(*iu), gfp); +	if (!iu) +		goto err; + +	iu->iu_id = IU_ID_TASK_MGMT; +	iu->tag = cpu_to_be16(stream_id); +	int_to_scsilun(cmnd->device->lun, &iu->lun); + +	iu->function = function; +	switch (function) { +	case TMF_ABORT_TASK: +		if (blk_rq_tagged(cmnd->request)) +			iu->task_tag = cpu_to_be16(cmnd->request->tag + 2); +		else +			iu->task_tag = cpu_to_be16(1); +		break; +	} + +	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu), +			  usb_free_urb, NULL); +	urb->transfer_flags |= URB_FREE_BUFFER; + +	err = usb_submit_urb(urb, gfp); +	if (err) +		goto err; + +	return 0; + +err: +	usb_free_urb(urb); +	return err; +} +  /*   * Why should I request the Status IU before sending the Command IU?  Spec   * says to, but also says the device may receive them in any order.  Seems   * daft to me.   */ -static int uas_submit_urbs(struct scsi_cmnd *cmnd, -					struct uas_dev_info *devinfo, gfp_t gfp) +static int uas_submit_sense_urb(struct Scsi_Host *shost, +				gfp_t gfp, unsigned int stream)  { -	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; +	struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; +	struct urb *urb; -	if (cmdinfo->state & ALLOC_STATUS_URB) { -		cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, -				cmnd->device->host, cmdinfo->stream); -		if (!cmdinfo->status_urb) -			return SCSI_MLQUEUE_DEVICE_BUSY; -		cmdinfo->state &= ~ALLOC_STATUS_URB; +	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream); +	if (!urb) +		return SCSI_MLQUEUE_DEVICE_BUSY; +	if (usb_submit_urb(urb, gfp)) { +		shost_printk(KERN_INFO, shost, +			     "sense urb submission failure\n"); +		usb_free_urb(urb); +		return SCSI_MLQUEUE_DEVICE_BUSY;  	} +	usb_anchor_urb(urb, &devinfo->sense_urbs); +	return 0; +} + +static int uas_submit_urbs(struct scsi_cmnd *cmnd, +			   struct uas_dev_info *devinfo, gfp_t gfp) +{ +	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; +	int err;  	if (cmdinfo->state & SUBMIT_STATUS_URB) { -		if (usb_submit_urb(cmdinfo->status_urb, gfp)) { -			scmd_printk(KERN_INFO, cmnd, -					"sense urb submission failure\n"); -			return SCSI_MLQUEUE_DEVICE_BUSY; +		err = uas_submit_sense_urb(cmnd->device->host, gfp, +					   cmdinfo->stream); +		if (err) { +			return err;  		}  		cmdinfo->state &= ~SUBMIT_STATUS_URB;  	}  	if (cmdinfo->state & ALLOC_DATA_IN_URB) {  		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, -					devinfo->data_in_pipe, cmnd, -					DMA_FROM_DEVICE); +					devinfo->data_in_pipe, cmdinfo->stream, +					cmnd, DMA_FROM_DEVICE);  		if (!cmdinfo->data_in_urb)  			return SCSI_MLQUEUE_DEVICE_BUSY;  		cmdinfo->state &= ~ALLOC_DATA_IN_URB; @@ -432,12 +495,14 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,  			return SCSI_MLQUEUE_DEVICE_BUSY;  		}  		cmdinfo->state &= ~SUBMIT_DATA_IN_URB; +		cmdinfo->state |= DATA_IN_URB_INFLIGHT; +		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);  	}  	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {  		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, -					devinfo->data_out_pipe, cmnd, -					DMA_TO_DEVICE); +					devinfo->data_out_pipe, cmdinfo->stream, +					cmnd, DMA_TO_DEVICE);  		if (!cmdinfo->data_out_urb)  			return SCSI_MLQUEUE_DEVICE_BUSY;  		cmdinfo->state &= ~ALLOC_DATA_OUT_URB; @@ -450,6 +515,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,  			return SCSI_MLQUEUE_DEVICE_BUSY;  		}  		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB; +		cmdinfo->state |= DATA_OUT_URB_INFLIGHT; +		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);  	}  	if (cmdinfo->state & ALLOC_CMD_URB) { @@ -467,6 +534,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,  			return SCSI_MLQUEUE_DEVICE_BUSY;  		}  		cmdinfo->state &= ~SUBMIT_CMD_URB; +		cmdinfo->state |= COMMAND_INFLIGHT;  	}  	return 0; @@ -494,8 +562,9 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,  	cmnd->scsi_done = done; -	cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB | +	cmdinfo->state = SUBMIT_STATUS_URB |  			ALLOC_CMD_URB | SUBMIT_CMD_URB; +	cmdinfo->aborted = 0;  	switch (cmnd->sc_data_direction) {  	case DMA_FROM_DEVICE: @@ -510,8 +579,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,  	}  	if (!devinfo->use_streams) { -		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB | -				ALLOC_STATUS_URB | SUBMIT_STATUS_URB); +		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);  		cmdinfo->stream = 0;  	} @@ -519,7 +587,6 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,  	if (err) {  		/* If we did nothing, give up now */  		if (cmdinfo->state & SUBMIT_STATUS_URB) { -			usb_free_urb(cmdinfo->status_urb);  			return SCSI_MLQUEUE_DEVICE_BUSY;  		}  		spin_lock(&uas_work_lock); @@ -533,36 +600,66 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,  static DEF_SCSI_QCMD(uas_queuecommand) -static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) +static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, +			    const char *fname, u8 function)  { -	struct scsi_device *sdev = cmnd->device; -	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, -							cmnd->request->tag); +	struct Scsi_Host *shost = cmnd->device->host; +	struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; +	u16 tag = 9999; /* FIXME */ -/* XXX: Send ABORT TASK Task Management command */ -	return FAILED; +	memset(&devinfo->response, 0, sizeof(devinfo->response)); +	if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) { +		shost_printk(KERN_INFO, shost, +			     "%s: %s: submit sense urb failed\n", +			     __func__, fname); +		return FAILED; +	} +	if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) { +		shost_printk(KERN_INFO, shost, +			     "%s: %s: submit task mgmt urb failed\n", +			     __func__, fname); +		return FAILED; +	} +	if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) { +		shost_printk(KERN_INFO, shost, +			     "%s: %s timed out\n", __func__, fname); +		return FAILED; +	} +	if (be16_to_cpu(devinfo->response.tag) != tag) { +		shost_printk(KERN_INFO, shost, +			     "%s: %s failed (wrong tag %d/%d)\n", __func__, +			     fname, be16_to_cpu(devinfo->response.tag), tag); +		return FAILED; +	} +	if (devinfo->response.response_code != RC_TMF_COMPLETE) { +		shost_printk(KERN_INFO, shost, +			     "%s: %s failed (rc 0x%x)\n", __func__, +			     fname, devinfo->response.response_code); +		return FAILED; +	} +	return SUCCESS;  } -static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) +static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)  { -	struct scsi_device *sdev = cmnd->device; -	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, -							cmnd->request->tag); +	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; +	int ret; -/* XXX: Send LOGICAL UNIT RESET Task Management command */ -	return FAILED; +	uas_log_cmd_state(cmnd, __func__); +	cmdinfo->aborted = 1; +	ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK); +	if (cmdinfo->state & DATA_IN_URB_INFLIGHT) +		usb_kill_urb(cmdinfo->data_in_urb); +	if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) +		usb_kill_urb(cmdinfo->data_out_urb); +	return ret;  } -static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd) +static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)  { -	struct scsi_device *sdev = cmnd->device; -	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, -							cmnd->request->tag); - -/* XXX: Can we reset just the one USB interface? - * Would calling usb_set_interface() have the right effect? - */ -	return FAILED; +	sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__); +	return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET", +				TMF_LOGICAL_UNIT_RESET);  }  static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) @@ -570,14 +667,21 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)  	struct scsi_device *sdev = cmnd->device;  	struct uas_dev_info *devinfo = sdev->hostdata;  	struct usb_device *udev = devinfo->udev; +	int err; -	sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, -							cmnd->request->tag); +	devinfo->resetting = 1; +	usb_kill_anchored_urbs(&devinfo->sense_urbs); +	usb_kill_anchored_urbs(&devinfo->data_urbs); +	err = usb_reset_device(udev); +	devinfo->resetting = 0; -	if (usb_reset_device(udev)) -		return SUCCESS; +	if (err) { +		shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__); +		return FAILED; +	} -	return FAILED; +	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__); +	return SUCCESS;  }  static int uas_slave_alloc(struct scsi_device *sdev) @@ -602,7 +706,6 @@ static struct scsi_host_template uas_host_template = {  	.slave_configure = uas_slave_configure,  	.eh_abort_handler = uas_eh_abort_handler,  	.eh_device_reset_handler = uas_eh_device_reset_handler, -	.eh_target_reset_handler = uas_eh_target_reset_handler,  	.eh_bus_reset_handler = uas_eh_bus_reset_handler,  	.can_queue = 65536,	/* Is there a limit on the _host_ ? */  	.this_id = -1, @@ -722,29 +825,6 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)  	}  } -static int uas_alloc_status_urb(struct uas_dev_info *devinfo, -		struct Scsi_Host *shost) -{ -	if (devinfo->use_streams) { -		devinfo->status_urb = NULL; -		return 0; -	} - -	devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL, -			shost, 0); -	if (!devinfo->status_urb) -		goto err_s_urb; - -	if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL)) -		goto err_submit_urb; - -	return 0; -err_submit_urb: -	usb_free_urb(devinfo->status_urb); -err_s_urb: -	return -ENOMEM; -} -  static void uas_free_streams(struct uas_dev_info *devinfo)  {  	struct usb_device *udev = devinfo->udev; @@ -787,6 +867,9 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)  	devinfo->intf = intf;  	devinfo->udev = udev; +	devinfo->resetting = 0; +	init_usb_anchor(&devinfo->sense_urbs); +	init_usb_anchor(&devinfo->data_urbs);  	uas_configure_endpoints(devinfo);  	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2); @@ -799,17 +882,10 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)  	shost->hostdata[0] = (unsigned long)devinfo; -	result = uas_alloc_status_urb(devinfo, shost); -	if (result) -		goto err_alloc_status; -  	scsi_scan_host(shost);  	usb_set_intfdata(intf, shost);  	return result; -err_alloc_status: -	scsi_remove_host(shost); -	shost = NULL;  deconfig_eps:  	uas_free_streams(devinfo);   free: @@ -837,8 +913,8 @@ static void uas_disconnect(struct usb_interface *intf)  	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];  	scsi_remove_host(shost); -	usb_kill_urb(devinfo->status_urb); -	usb_free_urb(devinfo->status_urb); +	usb_kill_anchored_urbs(&devinfo->sense_urbs); +	usb_kill_anchored_urbs(&devinfo->data_urbs);  	uas_free_streams(devinfo);  	kfree(devinfo);  }  |