162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * USB Attached SCSI
462306a36Sopenharmony_ci * Note that this is not the same as the USB Mass Storage driver
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016
762306a36Sopenharmony_ci * Copyright Matthew Wilcox for Intel Corp, 2010
862306a36Sopenharmony_ci * Copyright Sarah Sharp for Intel Corp, 2010
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/blkdev.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/usb.h>
1662306a36Sopenharmony_ci#include <linux/usb_usual.h>
1762306a36Sopenharmony_ci#include <linux/usb/hcd.h>
1862306a36Sopenharmony_ci#include <linux/usb/storage.h>
1962306a36Sopenharmony_ci#include <linux/usb/uas.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <scsi/scsi.h>
2262306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
2362306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
2462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
2562306a36Sopenharmony_ci#include <scsi/scsi_device.h>
2662306a36Sopenharmony_ci#include <scsi/scsi_host.h>
2762306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "uas-detect.h"
3062306a36Sopenharmony_ci#include "scsiglue.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define MAX_CMNDS 256
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct uas_dev_info {
3562306a36Sopenharmony_ci	struct usb_interface *intf;
3662306a36Sopenharmony_ci	struct usb_device *udev;
3762306a36Sopenharmony_ci	struct usb_anchor cmd_urbs;
3862306a36Sopenharmony_ci	struct usb_anchor sense_urbs;
3962306a36Sopenharmony_ci	struct usb_anchor data_urbs;
4062306a36Sopenharmony_ci	unsigned long flags;
4162306a36Sopenharmony_ci	int qdepth, resetting;
4262306a36Sopenharmony_ci	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
4362306a36Sopenharmony_ci	unsigned use_streams:1;
4462306a36Sopenharmony_ci	unsigned shutdown:1;
4562306a36Sopenharmony_ci	struct scsi_cmnd *cmnd[MAX_CMNDS];
4662306a36Sopenharmony_ci	spinlock_t lock;
4762306a36Sopenharmony_ci	struct work_struct work;
4862306a36Sopenharmony_ci	struct work_struct scan_work;      /* for async scanning */
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum {
5262306a36Sopenharmony_ci	SUBMIT_STATUS_URB	= BIT(1),
5362306a36Sopenharmony_ci	ALLOC_DATA_IN_URB	= BIT(2),
5462306a36Sopenharmony_ci	SUBMIT_DATA_IN_URB	= BIT(3),
5562306a36Sopenharmony_ci	ALLOC_DATA_OUT_URB	= BIT(4),
5662306a36Sopenharmony_ci	SUBMIT_DATA_OUT_URB	= BIT(5),
5762306a36Sopenharmony_ci	ALLOC_CMD_URB		= BIT(6),
5862306a36Sopenharmony_ci	SUBMIT_CMD_URB		= BIT(7),
5962306a36Sopenharmony_ci	COMMAND_INFLIGHT        = BIT(8),
6062306a36Sopenharmony_ci	DATA_IN_URB_INFLIGHT    = BIT(9),
6162306a36Sopenharmony_ci	DATA_OUT_URB_INFLIGHT   = BIT(10),
6262306a36Sopenharmony_ci	COMMAND_ABORTED         = BIT(11),
6362306a36Sopenharmony_ci	IS_IN_WORK_LIST         = BIT(12),
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Overrides scsi_pointer */
6762306a36Sopenharmony_cistruct uas_cmd_info {
6862306a36Sopenharmony_ci	unsigned int state;
6962306a36Sopenharmony_ci	unsigned int uas_tag;
7062306a36Sopenharmony_ci	struct urb *cmd_urb;
7162306a36Sopenharmony_ci	struct urb *data_in_urb;
7262306a36Sopenharmony_ci	struct urb *data_out_urb;
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* I hate forward declarations, but I actually have a loop */
7662306a36Sopenharmony_cistatic int uas_submit_urbs(struct scsi_cmnd *cmnd,
7762306a36Sopenharmony_ci				struct uas_dev_info *devinfo);
7862306a36Sopenharmony_cistatic void uas_do_work(struct work_struct *work);
7962306a36Sopenharmony_cistatic int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
8062306a36Sopenharmony_cistatic void uas_free_streams(struct uas_dev_info *devinfo);
8162306a36Sopenharmony_cistatic void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
8262306a36Sopenharmony_ci				int status);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/*
8562306a36Sopenharmony_ci * This driver needs its own workqueue, as we need to control memory allocation.
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * In the course of error handling and power management uas_wait_for_pending_cmnds()
8862306a36Sopenharmony_ci * needs to flush pending work items. In these contexts we cannot allocate memory
8962306a36Sopenharmony_ci * by doing block IO as we would deadlock. For the same reason we cannot wait
9062306a36Sopenharmony_ci * for anything allocating memory not heeding these constraints.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * So we have to control all work items that can be on the workqueue we flush.
9362306a36Sopenharmony_ci * Hence we cannot share a queue and need our own.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_cistatic struct workqueue_struct *workqueue;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void uas_do_work(struct work_struct *work)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct uas_dev_info *devinfo =
10062306a36Sopenharmony_ci		container_of(work, struct uas_dev_info, work);
10162306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo;
10262306a36Sopenharmony_ci	struct scsi_cmnd *cmnd;
10362306a36Sopenharmony_ci	unsigned long flags;
10462306a36Sopenharmony_ci	int i, err;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (devinfo->resetting)
10962306a36Sopenharmony_ci		goto out;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	for (i = 0; i < devinfo->qdepth; i++) {
11262306a36Sopenharmony_ci		if (!devinfo->cmnd[i])
11362306a36Sopenharmony_ci			continue;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		cmnd = devinfo->cmnd[i];
11662306a36Sopenharmony_ci		cmdinfo = scsi_cmd_priv(cmnd);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		if (!(cmdinfo->state & IS_IN_WORK_LIST))
11962306a36Sopenharmony_ci			continue;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
12262306a36Sopenharmony_ci		if (!err)
12362306a36Sopenharmony_ci			cmdinfo->state &= ~IS_IN_WORK_LIST;
12462306a36Sopenharmony_ci		else
12562306a36Sopenharmony_ci			queue_work(workqueue, &devinfo->work);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ciout:
12862306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void uas_scan_work(struct work_struct *work)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct uas_dev_info *devinfo =
13462306a36Sopenharmony_ci		container_of(work, struct uas_dev_info, scan_work);
13562306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(devinfo->intf);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	dev_dbg(&devinfo->intf->dev, "starting scan\n");
13862306a36Sopenharmony_ci	scsi_scan_host(shost);
13962306a36Sopenharmony_ci	dev_dbg(&devinfo->intf->dev, "scan complete\n");
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void uas_add_work(struct scsi_cmnd *cmnd)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
14562306a36Sopenharmony_ci	struct uas_dev_info *devinfo = cmnd->device->hostdata;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	lockdep_assert_held(&devinfo->lock);
14862306a36Sopenharmony_ci	cmdinfo->state |= IS_IN_WORK_LIST;
14962306a36Sopenharmony_ci	queue_work(workqueue, &devinfo->work);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void uas_zap_pending(struct uas_dev_info *devinfo, int result)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo;
15562306a36Sopenharmony_ci	struct scsi_cmnd *cmnd;
15662306a36Sopenharmony_ci	unsigned long flags;
15762306a36Sopenharmony_ci	int i, err;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
16062306a36Sopenharmony_ci	for (i = 0; i < devinfo->qdepth; i++) {
16162306a36Sopenharmony_ci		if (!devinfo->cmnd[i])
16262306a36Sopenharmony_ci			continue;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		cmnd = devinfo->cmnd[i];
16562306a36Sopenharmony_ci		cmdinfo = scsi_cmd_priv(cmnd);
16662306a36Sopenharmony_ci		uas_log_cmd_state(cmnd, __func__, 0);
16762306a36Sopenharmony_ci		/* Sense urbs were killed, clear COMMAND_INFLIGHT manually */
16862306a36Sopenharmony_ci		cmdinfo->state &= ~COMMAND_INFLIGHT;
16962306a36Sopenharmony_ci		cmnd->result = result << 16;
17062306a36Sopenharmony_ci		err = uas_try_complete(cmnd, __func__);
17162306a36Sopenharmony_ci		WARN_ON(err != 0);
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct sense_iu *sense_iu = urb->transfer_buffer;
17962306a36Sopenharmony_ci	struct scsi_device *sdev = cmnd->device;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (urb->actual_length > 16) {
18262306a36Sopenharmony_ci		unsigned len = be16_to_cpup(&sense_iu->len);
18362306a36Sopenharmony_ci		if (len + 16 != urb->actual_length) {
18462306a36Sopenharmony_ci			int newlen = min(len + 16, urb->actual_length) - 16;
18562306a36Sopenharmony_ci			if (newlen < 0)
18662306a36Sopenharmony_ci				newlen = 0;
18762306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
18862306a36Sopenharmony_ci				"disagrees with IU sense data length %d, "
18962306a36Sopenharmony_ci				"using %d bytes of sense data\n", __func__,
19062306a36Sopenharmony_ci					urb->actual_length, len, newlen);
19162306a36Sopenharmony_ci			len = newlen;
19262306a36Sopenharmony_ci		}
19362306a36Sopenharmony_ci		memcpy(cmnd->sense_buffer, sense_iu->sense, len);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	cmnd->result = sense_iu->status;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
20062306a36Sopenharmony_ci			      int status)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct uas_cmd_info *ci = scsi_cmd_priv(cmnd);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (status == -ENODEV) /* too late */
20562306a36Sopenharmony_ci		return;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	scmd_printk(KERN_INFO, cmnd,
20862306a36Sopenharmony_ci		    "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ",
20962306a36Sopenharmony_ci		    prefix, status, ci->uas_tag,
21062306a36Sopenharmony_ci		    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "",
21162306a36Sopenharmony_ci		    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "",
21262306a36Sopenharmony_ci		    (ci->state & SUBMIT_DATA_IN_URB)    ? " s-in"  : "",
21362306a36Sopenharmony_ci		    (ci->state & ALLOC_DATA_OUT_URB)    ? " a-out" : "",
21462306a36Sopenharmony_ci		    (ci->state & SUBMIT_DATA_OUT_URB)   ? " s-out" : "",
21562306a36Sopenharmony_ci		    (ci->state & ALLOC_CMD_URB)         ? " a-cmd" : "",
21662306a36Sopenharmony_ci		    (ci->state & SUBMIT_CMD_URB)        ? " s-cmd" : "",
21762306a36Sopenharmony_ci		    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "",
21862306a36Sopenharmony_ci		    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "",
21962306a36Sopenharmony_ci		    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "",
22062306a36Sopenharmony_ci		    (ci->state & COMMAND_ABORTED)       ? " abort" : "",
22162306a36Sopenharmony_ci		    (ci->state & IS_IN_WORK_LIST)       ? " work"  : "");
22262306a36Sopenharmony_ci	scsi_print_command(cmnd);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void uas_free_unsubmitted_urbs(struct scsi_cmnd *cmnd)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (!cmnd)
23062306a36Sopenharmony_ci		return;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	cmdinfo = scsi_cmd_priv(cmnd);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (cmdinfo->state & SUBMIT_CMD_URB)
23562306a36Sopenharmony_ci		usb_free_urb(cmdinfo->cmd_urb);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* data urbs may have never gotten their submit flag set */
23862306a36Sopenharmony_ci	if (!(cmdinfo->state & DATA_IN_URB_INFLIGHT))
23962306a36Sopenharmony_ci		usb_free_urb(cmdinfo->data_in_urb);
24062306a36Sopenharmony_ci	if (!(cmdinfo->state & DATA_OUT_URB_INFLIGHT))
24162306a36Sopenharmony_ci		usb_free_urb(cmdinfo->data_out_urb);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
24762306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	lockdep_assert_held(&devinfo->lock);
25062306a36Sopenharmony_ci	if (cmdinfo->state & (COMMAND_INFLIGHT |
25162306a36Sopenharmony_ci			      DATA_IN_URB_INFLIGHT |
25262306a36Sopenharmony_ci			      DATA_OUT_URB_INFLIGHT |
25362306a36Sopenharmony_ci			      COMMAND_ABORTED))
25462306a36Sopenharmony_ci		return -EBUSY;
25562306a36Sopenharmony_ci	devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
25662306a36Sopenharmony_ci	uas_free_unsubmitted_urbs(cmnd);
25762306a36Sopenharmony_ci	scsi_done(cmnd);
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
26262306a36Sopenharmony_ci			  unsigned direction)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
26562306a36Sopenharmony_ci	int err;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
26862306a36Sopenharmony_ci	err = uas_submit_urbs(cmnd, cmnd->device->hostdata);
26962306a36Sopenharmony_ci	if (err) {
27062306a36Sopenharmony_ci		uas_add_work(cmnd);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd *cmnd)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	u8 response_code = riu->response_code;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	switch (response_code) {
27962306a36Sopenharmony_ci	case RC_INCORRECT_LUN:
28062306a36Sopenharmony_ci		set_host_byte(cmnd, DID_BAD_TARGET);
28162306a36Sopenharmony_ci		break;
28262306a36Sopenharmony_ci	case RC_TMF_SUCCEEDED:
28362306a36Sopenharmony_ci		set_host_byte(cmnd, DID_OK);
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	case RC_TMF_NOT_SUPPORTED:
28662306a36Sopenharmony_ci		set_host_byte(cmnd, DID_BAD_TARGET);
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci	default:
28962306a36Sopenharmony_ci		uas_log_cmd_state(cmnd, "response iu", response_code);
29062306a36Sopenharmony_ci		set_host_byte(cmnd, DID_ERROR);
29162306a36Sopenharmony_ci		break;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return response_code == RC_TMF_SUCCEEDED;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void uas_stat_cmplt(struct urb *urb)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct iu *iu = urb->transfer_buffer;
30062306a36Sopenharmony_ci	struct Scsi_Host *shost = urb->context;
30162306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
30262306a36Sopenharmony_ci	struct urb *data_in_urb = NULL;
30362306a36Sopenharmony_ci	struct urb *data_out_urb = NULL;
30462306a36Sopenharmony_ci	struct scsi_cmnd *cmnd;
30562306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo;
30662306a36Sopenharmony_ci	unsigned long flags;
30762306a36Sopenharmony_ci	unsigned int idx;
30862306a36Sopenharmony_ci	int status = urb->status;
30962306a36Sopenharmony_ci	bool success;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (devinfo->resetting)
31462306a36Sopenharmony_ci		goto out;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (status) {
31762306a36Sopenharmony_ci		if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN)
31862306a36Sopenharmony_ci			dev_err(&urb->dev->dev, "stat urb: status %d\n", status);
31962306a36Sopenharmony_ci		goto out;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	idx = be16_to_cpup(&iu->tag) - 1;
32362306a36Sopenharmony_ci	if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) {
32462306a36Sopenharmony_ci		dev_err(&urb->dev->dev,
32562306a36Sopenharmony_ci			"stat urb: no pending cmd for uas-tag %d\n", idx + 1);
32662306a36Sopenharmony_ci		goto out;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	cmnd = devinfo->cmnd[idx];
33062306a36Sopenharmony_ci	cmdinfo = scsi_cmd_priv(cmnd);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (!(cmdinfo->state & COMMAND_INFLIGHT)) {
33362306a36Sopenharmony_ci		uas_log_cmd_state(cmnd, "unexpected status cmplt", 0);
33462306a36Sopenharmony_ci		goto out;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	switch (iu->iu_id) {
33862306a36Sopenharmony_ci	case IU_ID_STATUS:
33962306a36Sopenharmony_ci		uas_sense(urb, cmnd);
34062306a36Sopenharmony_ci		if (cmnd->result != 0) {
34162306a36Sopenharmony_ci			/* cancel data transfers on error */
34262306a36Sopenharmony_ci			data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
34362306a36Sopenharmony_ci			data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
34462306a36Sopenharmony_ci		}
34562306a36Sopenharmony_ci		cmdinfo->state &= ~COMMAND_INFLIGHT;
34662306a36Sopenharmony_ci		uas_try_complete(cmnd, __func__);
34762306a36Sopenharmony_ci		break;
34862306a36Sopenharmony_ci	case IU_ID_READ_READY:
34962306a36Sopenharmony_ci		if (!cmdinfo->data_in_urb ||
35062306a36Sopenharmony_ci				(cmdinfo->state & DATA_IN_URB_INFLIGHT)) {
35162306a36Sopenharmony_ci			uas_log_cmd_state(cmnd, "unexpected read rdy", 0);
35262306a36Sopenharmony_ci			break;
35362306a36Sopenharmony_ci		}
35462306a36Sopenharmony_ci		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
35562306a36Sopenharmony_ci		break;
35662306a36Sopenharmony_ci	case IU_ID_WRITE_READY:
35762306a36Sopenharmony_ci		if (!cmdinfo->data_out_urb ||
35862306a36Sopenharmony_ci				(cmdinfo->state & DATA_OUT_URB_INFLIGHT)) {
35962306a36Sopenharmony_ci			uas_log_cmd_state(cmnd, "unexpected write rdy", 0);
36062306a36Sopenharmony_ci			break;
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
36362306a36Sopenharmony_ci		break;
36462306a36Sopenharmony_ci	case IU_ID_RESPONSE:
36562306a36Sopenharmony_ci		cmdinfo->state &= ~COMMAND_INFLIGHT;
36662306a36Sopenharmony_ci		success = uas_evaluate_response_iu((struct response_iu *)iu, cmnd);
36762306a36Sopenharmony_ci		if (!success) {
36862306a36Sopenharmony_ci			/* Error, cancel data transfers */
36962306a36Sopenharmony_ci			data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
37062306a36Sopenharmony_ci			data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci		uas_try_complete(cmnd, __func__);
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci	default:
37562306a36Sopenharmony_ci		uas_log_cmd_state(cmnd, "bogus IU", iu->iu_id);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ciout:
37862306a36Sopenharmony_ci	usb_free_urb(urb);
37962306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Unlinking of data urbs must be done without holding the lock */
38262306a36Sopenharmony_ci	if (data_in_urb) {
38362306a36Sopenharmony_ci		usb_unlink_urb(data_in_urb);
38462306a36Sopenharmony_ci		usb_put_urb(data_in_urb);
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci	if (data_out_urb) {
38762306a36Sopenharmony_ci		usb_unlink_urb(data_out_urb);
38862306a36Sopenharmony_ci		usb_put_urb(data_out_urb);
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic void uas_data_cmplt(struct urb *urb)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct scsi_cmnd *cmnd = urb->context;
39562306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
39662306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
39762306a36Sopenharmony_ci	struct scsi_data_buffer *sdb = &cmnd->sdb;
39862306a36Sopenharmony_ci	unsigned long flags;
39962306a36Sopenharmony_ci	int status = urb->status;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (cmdinfo->data_in_urb == urb) {
40462306a36Sopenharmony_ci		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
40562306a36Sopenharmony_ci		cmdinfo->data_in_urb = NULL;
40662306a36Sopenharmony_ci	} else if (cmdinfo->data_out_urb == urb) {
40762306a36Sopenharmony_ci		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
40862306a36Sopenharmony_ci		cmdinfo->data_out_urb = NULL;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (devinfo->resetting)
41262306a36Sopenharmony_ci		goto out;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Data urbs should not complete before the cmd urb is submitted */
41562306a36Sopenharmony_ci	if (cmdinfo->state & SUBMIT_CMD_URB) {
41662306a36Sopenharmony_ci		uas_log_cmd_state(cmnd, "unexpected data cmplt", 0);
41762306a36Sopenharmony_ci		goto out;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (status) {
42162306a36Sopenharmony_ci		if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN)
42262306a36Sopenharmony_ci			uas_log_cmd_state(cmnd, "data cmplt err", status);
42362306a36Sopenharmony_ci		/* error: no data transfered */
42462306a36Sopenharmony_ci		scsi_set_resid(cmnd, sdb->length);
42562306a36Sopenharmony_ci	} else {
42662306a36Sopenharmony_ci		scsi_set_resid(cmnd, sdb->length - urb->actual_length);
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci	uas_try_complete(cmnd, __func__);
42962306a36Sopenharmony_ciout:
43062306a36Sopenharmony_ci	usb_free_urb(urb);
43162306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void uas_cmd_cmplt(struct urb *urb)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	if (urb->status)
43762306a36Sopenharmony_ci		dev_err(&urb->dev->dev, "cmd cmplt err %d\n", urb->status);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	usb_free_urb(urb);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
44362306a36Sopenharmony_ci				      struct scsi_cmnd *cmnd,
44462306a36Sopenharmony_ci				      enum dma_data_direction dir)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct usb_device *udev = devinfo->udev;
44762306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
44862306a36Sopenharmony_ci	struct urb *urb = usb_alloc_urb(0, gfp);
44962306a36Sopenharmony_ci	struct scsi_data_buffer *sdb = &cmnd->sdb;
45062306a36Sopenharmony_ci	unsigned int pipe = (dir == DMA_FROM_DEVICE)
45162306a36Sopenharmony_ci		? devinfo->data_in_pipe : devinfo->data_out_pipe;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (!urb)
45462306a36Sopenharmony_ci		goto out;
45562306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
45662306a36Sopenharmony_ci			  uas_data_cmplt, cmnd);
45762306a36Sopenharmony_ci	if (devinfo->use_streams)
45862306a36Sopenharmony_ci		urb->stream_id = cmdinfo->uas_tag;
45962306a36Sopenharmony_ci	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
46062306a36Sopenharmony_ci	urb->sg = sdb->table.sgl;
46162306a36Sopenharmony_ci out:
46262306a36Sopenharmony_ci	return urb;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
46662306a36Sopenharmony_ci				       struct scsi_cmnd *cmnd)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct usb_device *udev = devinfo->udev;
46962306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
47062306a36Sopenharmony_ci	struct urb *urb = usb_alloc_urb(0, gfp);
47162306a36Sopenharmony_ci	struct sense_iu *iu;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (!urb)
47462306a36Sopenharmony_ci		goto out;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	iu = kzalloc(sizeof(*iu), gfp);
47762306a36Sopenharmony_ci	if (!iu)
47862306a36Sopenharmony_ci		goto free;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
48162306a36Sopenharmony_ci			  uas_stat_cmplt, cmnd->device->host);
48262306a36Sopenharmony_ci	if (devinfo->use_streams)
48362306a36Sopenharmony_ci		urb->stream_id = cmdinfo->uas_tag;
48462306a36Sopenharmony_ci	urb->transfer_flags |= URB_FREE_BUFFER;
48562306a36Sopenharmony_ci out:
48662306a36Sopenharmony_ci	return urb;
48762306a36Sopenharmony_ci free:
48862306a36Sopenharmony_ci	usb_free_urb(urb);
48962306a36Sopenharmony_ci	return NULL;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
49362306a36Sopenharmony_ci					struct scsi_cmnd *cmnd)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct usb_device *udev = devinfo->udev;
49662306a36Sopenharmony_ci	struct scsi_device *sdev = cmnd->device;
49762306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
49862306a36Sopenharmony_ci	struct urb *urb = usb_alloc_urb(0, gfp);
49962306a36Sopenharmony_ci	struct command_iu *iu;
50062306a36Sopenharmony_ci	int len;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (!urb)
50362306a36Sopenharmony_ci		goto out;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	len = cmnd->cmd_len - 16;
50662306a36Sopenharmony_ci	if (len < 0)
50762306a36Sopenharmony_ci		len = 0;
50862306a36Sopenharmony_ci	len = ALIGN(len, 4);
50962306a36Sopenharmony_ci	iu = kzalloc(sizeof(*iu) + len, gfp);
51062306a36Sopenharmony_ci	if (!iu)
51162306a36Sopenharmony_ci		goto free;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	iu->iu_id = IU_ID_COMMAND;
51462306a36Sopenharmony_ci	iu->tag = cpu_to_be16(cmdinfo->uas_tag);
51562306a36Sopenharmony_ci	iu->prio_attr = UAS_SIMPLE_TAG;
51662306a36Sopenharmony_ci	iu->len = len;
51762306a36Sopenharmony_ci	int_to_scsilun(sdev->lun, &iu->lun);
51862306a36Sopenharmony_ci	memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len,
52162306a36Sopenharmony_ci							uas_cmd_cmplt, NULL);
52262306a36Sopenharmony_ci	urb->transfer_flags |= URB_FREE_BUFFER;
52362306a36Sopenharmony_ci out:
52462306a36Sopenharmony_ci	return urb;
52562306a36Sopenharmony_ci free:
52662306a36Sopenharmony_ci	usb_free_urb(urb);
52762306a36Sopenharmony_ci	return NULL;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/*
53162306a36Sopenharmony_ci * Why should I request the Status IU before sending the Command IU?  Spec
53262306a36Sopenharmony_ci * says to, but also says the device may receive them in any order.  Seems
53362306a36Sopenharmony_ci * daft to me.
53462306a36Sopenharmony_ci */
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd, gfp_t gfp)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct uas_dev_info *devinfo = cmnd->device->hostdata;
53962306a36Sopenharmony_ci	struct urb *urb;
54062306a36Sopenharmony_ci	int err;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	urb = uas_alloc_sense_urb(devinfo, gfp, cmnd);
54362306a36Sopenharmony_ci	if (!urb)
54462306a36Sopenharmony_ci		return NULL;
54562306a36Sopenharmony_ci	usb_anchor_urb(urb, &devinfo->sense_urbs);
54662306a36Sopenharmony_ci	err = usb_submit_urb(urb, gfp);
54762306a36Sopenharmony_ci	if (err) {
54862306a36Sopenharmony_ci		usb_unanchor_urb(urb);
54962306a36Sopenharmony_ci		uas_log_cmd_state(cmnd, "sense submit err", err);
55062306a36Sopenharmony_ci		usb_free_urb(urb);
55162306a36Sopenharmony_ci		return NULL;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	return urb;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic int uas_submit_urbs(struct scsi_cmnd *cmnd,
55762306a36Sopenharmony_ci			   struct uas_dev_info *devinfo)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
56062306a36Sopenharmony_ci	struct urb *urb;
56162306a36Sopenharmony_ci	int err;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	lockdep_assert_held(&devinfo->lock);
56462306a36Sopenharmony_ci	if (cmdinfo->state & SUBMIT_STATUS_URB) {
56562306a36Sopenharmony_ci		urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC);
56662306a36Sopenharmony_ci		if (!urb)
56762306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
56862306a36Sopenharmony_ci		cmdinfo->state &= ~SUBMIT_STATUS_URB;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
57262306a36Sopenharmony_ci		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC,
57362306a36Sopenharmony_ci							cmnd, DMA_FROM_DEVICE);
57462306a36Sopenharmony_ci		if (!cmdinfo->data_in_urb)
57562306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
57662306a36Sopenharmony_ci		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
58062306a36Sopenharmony_ci		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
58162306a36Sopenharmony_ci		err = usb_submit_urb(cmdinfo->data_in_urb, GFP_ATOMIC);
58262306a36Sopenharmony_ci		if (err) {
58362306a36Sopenharmony_ci			usb_unanchor_urb(cmdinfo->data_in_urb);
58462306a36Sopenharmony_ci			uas_log_cmd_state(cmnd, "data in submit err", err);
58562306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
58862306a36Sopenharmony_ci		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
59262306a36Sopenharmony_ci		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC,
59362306a36Sopenharmony_ci							cmnd, DMA_TO_DEVICE);
59462306a36Sopenharmony_ci		if (!cmdinfo->data_out_urb)
59562306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
59662306a36Sopenharmony_ci		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
60062306a36Sopenharmony_ci		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
60162306a36Sopenharmony_ci		err = usb_submit_urb(cmdinfo->data_out_urb, GFP_ATOMIC);
60262306a36Sopenharmony_ci		if (err) {
60362306a36Sopenharmony_ci			usb_unanchor_urb(cmdinfo->data_out_urb);
60462306a36Sopenharmony_ci			uas_log_cmd_state(cmnd, "data out submit err", err);
60562306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
60862306a36Sopenharmony_ci		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (cmdinfo->state & ALLOC_CMD_URB) {
61262306a36Sopenharmony_ci		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, GFP_ATOMIC, cmnd);
61362306a36Sopenharmony_ci		if (!cmdinfo->cmd_urb)
61462306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
61562306a36Sopenharmony_ci		cmdinfo->state &= ~ALLOC_CMD_URB;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (cmdinfo->state & SUBMIT_CMD_URB) {
61962306a36Sopenharmony_ci		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
62062306a36Sopenharmony_ci		err = usb_submit_urb(cmdinfo->cmd_urb, GFP_ATOMIC);
62162306a36Sopenharmony_ci		if (err) {
62262306a36Sopenharmony_ci			usb_unanchor_urb(cmdinfo->cmd_urb);
62362306a36Sopenharmony_ci			uas_log_cmd_state(cmnd, "cmd submit err", err);
62462306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
62562306a36Sopenharmony_ci		}
62662306a36Sopenharmony_ci		cmdinfo->cmd_urb = NULL;
62762306a36Sopenharmony_ci		cmdinfo->state &= ~SUBMIT_CMD_URB;
62862306a36Sopenharmony_ci		cmdinfo->state |= COMMAND_INFLIGHT;
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return 0;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic int uas_queuecommand_lck(struct scsi_cmnd *cmnd)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct scsi_device *sdev = cmnd->device;
63762306a36Sopenharmony_ci	struct uas_dev_info *devinfo = sdev->hostdata;
63862306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
63962306a36Sopenharmony_ci	unsigned long flags;
64062306a36Sopenharmony_ci	int idx, err;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/* Re-check scsi_block_requests now that we've the host-lock */
64362306a36Sopenharmony_ci	if (cmnd->device->host->host_self_blocked)
64462306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if ((devinfo->flags & US_FL_NO_ATA_1X) &&
64762306a36Sopenharmony_ci			(cmnd->cmnd[0] == ATA_12 || cmnd->cmnd[0] == ATA_16)) {
64862306a36Sopenharmony_ci		memcpy(cmnd->sense_buffer, usb_stor_sense_invalidCDB,
64962306a36Sopenharmony_ci		       sizeof(usb_stor_sense_invalidCDB));
65062306a36Sopenharmony_ci		cmnd->result = SAM_STAT_CHECK_CONDITION;
65162306a36Sopenharmony_ci		scsi_done(cmnd);
65262306a36Sopenharmony_ci		return 0;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (devinfo->resetting) {
65862306a36Sopenharmony_ci		set_host_byte(cmnd, DID_ERROR);
65962306a36Sopenharmony_ci		scsi_done(cmnd);
66062306a36Sopenharmony_ci		goto zombie;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* Find a free uas-tag */
66462306a36Sopenharmony_ci	for (idx = 0; idx < devinfo->qdepth; idx++) {
66562306a36Sopenharmony_ci		if (!devinfo->cmnd[idx])
66662306a36Sopenharmony_ci			break;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	if (idx == devinfo->qdepth) {
66962306a36Sopenharmony_ci		spin_unlock_irqrestore(&devinfo->lock, flags);
67062306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	memset(cmdinfo, 0, sizeof(*cmdinfo));
67462306a36Sopenharmony_ci	cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */
67562306a36Sopenharmony_ci	cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	switch (cmnd->sc_data_direction) {
67862306a36Sopenharmony_ci	case DMA_FROM_DEVICE:
67962306a36Sopenharmony_ci		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci	case DMA_BIDIRECTIONAL:
68262306a36Sopenharmony_ci		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
68362306a36Sopenharmony_ci		fallthrough;
68462306a36Sopenharmony_ci	case DMA_TO_DEVICE:
68562306a36Sopenharmony_ci		cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci	case DMA_NONE:
68862306a36Sopenharmony_ci		break;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (!devinfo->use_streams)
69262306a36Sopenharmony_ci		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	err = uas_submit_urbs(cmnd, devinfo);
69562306a36Sopenharmony_ci	/*
69662306a36Sopenharmony_ci	 * in case of fatal errors the SCSI layer is peculiar
69762306a36Sopenharmony_ci	 * a command that has finished is a success for the purpose
69862306a36Sopenharmony_ci	 * of queueing, no matter how fatal the error
69962306a36Sopenharmony_ci	 */
70062306a36Sopenharmony_ci	if (err == -ENODEV) {
70162306a36Sopenharmony_ci		set_host_byte(cmnd, DID_ERROR);
70262306a36Sopenharmony_ci		scsi_done(cmnd);
70362306a36Sopenharmony_ci		goto zombie;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci	if (err) {
70662306a36Sopenharmony_ci		/* If we did nothing, give up now */
70762306a36Sopenharmony_ci		if (cmdinfo->state & SUBMIT_STATUS_URB) {
70862306a36Sopenharmony_ci			spin_unlock_irqrestore(&devinfo->lock, flags);
70962306a36Sopenharmony_ci			return SCSI_MLQUEUE_DEVICE_BUSY;
71062306a36Sopenharmony_ci		}
71162306a36Sopenharmony_ci		uas_add_work(cmnd);
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	devinfo->cmnd[idx] = cmnd;
71562306a36Sopenharmony_cizombie:
71662306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
71762306a36Sopenharmony_ci	return 0;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic DEF_SCSI_QCMD(uas_queuecommand)
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci/*
72362306a36Sopenharmony_ci * For now we do not support actually sending an abort to the device, so
72462306a36Sopenharmony_ci * this eh always fails. Still we must define it to make sure that we've
72562306a36Sopenharmony_ci * dropped all references to the cmnd in question once this function exits.
72662306a36Sopenharmony_ci */
72762306a36Sopenharmony_cistatic int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd);
73062306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
73162306a36Sopenharmony_ci	struct urb *data_in_urb = NULL;
73262306a36Sopenharmony_ci	struct urb *data_out_urb = NULL;
73362306a36Sopenharmony_ci	unsigned long flags;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	uas_log_cmd_state(cmnd, __func__, 0);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* Ensure that try_complete does not call scsi_done */
74062306a36Sopenharmony_ci	cmdinfo->state |= COMMAND_ABORTED;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Drop all refs to this cmnd, kill data urbs to break their ref */
74362306a36Sopenharmony_ci	devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
74462306a36Sopenharmony_ci	if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
74562306a36Sopenharmony_ci		data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
74662306a36Sopenharmony_ci	if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
74762306a36Sopenharmony_ci		data_out_urb = usb_get_urb(cmdinfo->data_out_urb);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	uas_free_unsubmitted_urbs(cmnd);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (data_in_urb) {
75462306a36Sopenharmony_ci		usb_kill_urb(data_in_urb);
75562306a36Sopenharmony_ci		usb_put_urb(data_in_urb);
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci	if (data_out_urb) {
75862306a36Sopenharmony_ci		usb_kill_urb(data_out_urb);
75962306a36Sopenharmony_ci		usb_put_urb(data_out_urb);
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	return FAILED;
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	struct scsi_device *sdev = cmnd->device;
76862306a36Sopenharmony_ci	struct uas_dev_info *devinfo = sdev->hostdata;
76962306a36Sopenharmony_ci	struct usb_device *udev = devinfo->udev;
77062306a36Sopenharmony_ci	unsigned long flags;
77162306a36Sopenharmony_ci	int err;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	err = usb_lock_device_for_reset(udev, devinfo->intf);
77462306a36Sopenharmony_ci	if (err) {
77562306a36Sopenharmony_ci		shost_printk(KERN_ERR, sdev->host,
77662306a36Sopenharmony_ci			     "%s FAILED to get lock err %d\n", __func__, err);
77762306a36Sopenharmony_ci		return FAILED;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
78362306a36Sopenharmony_ci	devinfo->resetting = 1;
78462306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
78762306a36Sopenharmony_ci	usb_kill_anchored_urbs(&devinfo->sense_urbs);
78862306a36Sopenharmony_ci	usb_kill_anchored_urbs(&devinfo->data_urbs);
78962306a36Sopenharmony_ci	uas_zap_pending(devinfo, DID_RESET);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	err = usb_reset_device(udev);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
79462306a36Sopenharmony_ci	devinfo->resetting = 0;
79562306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	usb_unlock_device(udev);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (err) {
80062306a36Sopenharmony_ci		shost_printk(KERN_INFO, sdev->host, "%s FAILED err %d\n",
80162306a36Sopenharmony_ci			     __func__, err);
80262306a36Sopenharmony_ci		return FAILED;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
80662306a36Sopenharmony_ci	return SUCCESS;
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic int uas_target_alloc(struct scsi_target *starget)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)
81262306a36Sopenharmony_ci			dev_to_shost(starget->dev.parent)->hostdata;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (devinfo->flags & US_FL_NO_REPORT_LUNS)
81562306a36Sopenharmony_ci		starget->no_report_luns = 1;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	return 0;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic int uas_slave_alloc(struct scsi_device *sdev)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct uas_dev_info *devinfo =
82362306a36Sopenharmony_ci		(struct uas_dev_info *)sdev->host->hostdata;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	sdev->hostdata = devinfo;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/*
82862306a36Sopenharmony_ci	 * The protocol has no requirements on alignment in the strict sense.
82962306a36Sopenharmony_ci	 * Controllers may or may not have alignment restrictions.
83062306a36Sopenharmony_ci	 * As this is not exported, we use an extremely conservative guess.
83162306a36Sopenharmony_ci	 */
83262306a36Sopenharmony_ci	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (devinfo->flags & US_FL_MAX_SECTORS_64)
83562306a36Sopenharmony_ci		blk_queue_max_hw_sectors(sdev->request_queue, 64);
83662306a36Sopenharmony_ci	else if (devinfo->flags & US_FL_MAX_SECTORS_240)
83762306a36Sopenharmony_ci		blk_queue_max_hw_sectors(sdev->request_queue, 240);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	return 0;
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic int uas_slave_configure(struct scsi_device *sdev)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	struct uas_dev_info *devinfo = sdev->hostdata;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
84762306a36Sopenharmony_ci		sdev->no_report_opcodes = 1;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* A few buggy USB-ATA bridges don't understand FUA */
85062306a36Sopenharmony_ci	if (devinfo->flags & US_FL_BROKEN_FUA)
85162306a36Sopenharmony_ci		sdev->broken_fua = 1;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* UAS also needs to support FL_ALWAYS_SYNC */
85462306a36Sopenharmony_ci	if (devinfo->flags & US_FL_ALWAYS_SYNC) {
85562306a36Sopenharmony_ci		sdev->skip_ms_page_3f = 1;
85662306a36Sopenharmony_ci		sdev->skip_ms_page_8 = 1;
85762306a36Sopenharmony_ci		sdev->wce_default_on = 1;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	/* Some disks cannot handle READ_CAPACITY_16 */
86162306a36Sopenharmony_ci	if (devinfo->flags & US_FL_NO_READ_CAPACITY_16)
86262306a36Sopenharmony_ci		sdev->no_read_capacity_16 = 1;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	/* Some disks cannot handle WRITE_SAME */
86562306a36Sopenharmony_ci	if (devinfo->flags & US_FL_NO_SAME)
86662306a36Sopenharmony_ci		sdev->no_write_same = 1;
86762306a36Sopenharmony_ci	/*
86862306a36Sopenharmony_ci	 * Some disks return the total number of blocks in response
86962306a36Sopenharmony_ci	 * to READ CAPACITY rather than the highest block number.
87062306a36Sopenharmony_ci	 * If this device makes that mistake, tell the sd driver.
87162306a36Sopenharmony_ci	 */
87262306a36Sopenharmony_ci	if (devinfo->flags & US_FL_FIX_CAPACITY)
87362306a36Sopenharmony_ci		sdev->fix_capacity = 1;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/*
87662306a36Sopenharmony_ci	 * in some cases we have to guess
87762306a36Sopenharmony_ci	 */
87862306a36Sopenharmony_ci	if (devinfo->flags & US_FL_CAPACITY_HEURISTICS)
87962306a36Sopenharmony_ci		sdev->guess_capacity = 1;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/*
88262306a36Sopenharmony_ci	 * Some devices report generic values until the media has been
88362306a36Sopenharmony_ci	 * accessed. Force a READ(10) prior to querying device
88462306a36Sopenharmony_ci	 * characteristics.
88562306a36Sopenharmony_ci	 */
88662306a36Sopenharmony_ci	sdev->read_before_ms = 1;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/*
88962306a36Sopenharmony_ci	 * Some devices don't like MODE SENSE with page=0x3f,
89062306a36Sopenharmony_ci	 * which is the command used for checking if a device
89162306a36Sopenharmony_ci	 * is write-protected.  Now that we tell the sd driver
89262306a36Sopenharmony_ci	 * to do a 192-byte transfer with this command the
89362306a36Sopenharmony_ci	 * majority of devices work fine, but a few still can't
89462306a36Sopenharmony_ci	 * handle it.  The sd driver will simply assume those
89562306a36Sopenharmony_ci	 * devices are write-enabled.
89662306a36Sopenharmony_ci	 */
89762306a36Sopenharmony_ci	if (devinfo->flags & US_FL_NO_WP_DETECT)
89862306a36Sopenharmony_ci		sdev->skip_ms_page_3f = 1;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
90162306a36Sopenharmony_ci	return 0;
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic const struct scsi_host_template uas_host_template = {
90562306a36Sopenharmony_ci	.module = THIS_MODULE,
90662306a36Sopenharmony_ci	.name = "uas",
90762306a36Sopenharmony_ci	.queuecommand = uas_queuecommand,
90862306a36Sopenharmony_ci	.target_alloc = uas_target_alloc,
90962306a36Sopenharmony_ci	.slave_alloc = uas_slave_alloc,
91062306a36Sopenharmony_ci	.slave_configure = uas_slave_configure,
91162306a36Sopenharmony_ci	.eh_abort_handler = uas_eh_abort_handler,
91262306a36Sopenharmony_ci	.eh_device_reset_handler = uas_eh_device_reset_handler,
91362306a36Sopenharmony_ci	.this_id = -1,
91462306a36Sopenharmony_ci	.skip_settle_delay = 1,
91562306a36Sopenharmony_ci	.dma_boundary = PAGE_SIZE - 1,
91662306a36Sopenharmony_ci	.cmd_size = sizeof(struct uas_cmd_info),
91762306a36Sopenharmony_ci};
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
92062306a36Sopenharmony_ci		    vendorName, productName, useProtocol, useTransport, \
92162306a36Sopenharmony_ci		    initFunction, flags) \
92262306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
92362306a36Sopenharmony_ci	.driver_info = (flags) }
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic struct usb_device_id uas_usb_ids[] = {
92662306a36Sopenharmony_ci#	include "unusual_uas.h"
92762306a36Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
92862306a36Sopenharmony_ci	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
92962306a36Sopenharmony_ci	{ }
93062306a36Sopenharmony_ci};
93162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, uas_usb_ids);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci#undef UNUSUAL_DEV
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic int uas_switch_interface(struct usb_device *udev,
93662306a36Sopenharmony_ci				struct usb_interface *intf)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	struct usb_host_interface *alt;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	alt = uas_find_uas_alt_setting(intf);
94162306a36Sopenharmony_ci	if (!alt)
94262306a36Sopenharmony_ci		return -ENODEV;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	return usb_set_interface(udev, alt->desc.bInterfaceNumber,
94562306a36Sopenharmony_ci			alt->desc.bAlternateSetting);
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic int uas_configure_endpoints(struct uas_dev_info *devinfo)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct usb_host_endpoint *eps[4] = { };
95162306a36Sopenharmony_ci	struct usb_device *udev = devinfo->udev;
95262306a36Sopenharmony_ci	int r;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
95562306a36Sopenharmony_ci	if (r)
95662306a36Sopenharmony_ci		return r;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	devinfo->cmd_pipe = usb_sndbulkpipe(udev,
95962306a36Sopenharmony_ci					    usb_endpoint_num(&eps[0]->desc));
96062306a36Sopenharmony_ci	devinfo->status_pipe = usb_rcvbulkpipe(udev,
96162306a36Sopenharmony_ci					    usb_endpoint_num(&eps[1]->desc));
96262306a36Sopenharmony_ci	devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
96362306a36Sopenharmony_ci					    usb_endpoint_num(&eps[2]->desc));
96462306a36Sopenharmony_ci	devinfo->data_out_pipe = usb_sndbulkpipe(udev,
96562306a36Sopenharmony_ci					    usb_endpoint_num(&eps[3]->desc));
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	if (udev->speed < USB_SPEED_SUPER) {
96862306a36Sopenharmony_ci		devinfo->qdepth = 32;
96962306a36Sopenharmony_ci		devinfo->use_streams = 0;
97062306a36Sopenharmony_ci	} else {
97162306a36Sopenharmony_ci		devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
97262306a36Sopenharmony_ci						    3, MAX_CMNDS, GFP_NOIO);
97362306a36Sopenharmony_ci		if (devinfo->qdepth < 0)
97462306a36Sopenharmony_ci			return devinfo->qdepth;
97562306a36Sopenharmony_ci		devinfo->use_streams = 1;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return 0;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic void uas_free_streams(struct uas_dev_info *devinfo)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct usb_device *udev = devinfo->udev;
98462306a36Sopenharmony_ci	struct usb_host_endpoint *eps[3];
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
98762306a36Sopenharmony_ci	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
98862306a36Sopenharmony_ci	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
98962306a36Sopenharmony_ci	usb_free_streams(devinfo->intf, eps, 3, GFP_NOIO);
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	int result = -ENOMEM;
99562306a36Sopenharmony_ci	struct Scsi_Host *shost = NULL;
99662306a36Sopenharmony_ci	struct uas_dev_info *devinfo;
99762306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(intf);
99862306a36Sopenharmony_ci	unsigned long dev_flags;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (!uas_use_uas_driver(intf, id, &dev_flags))
100162306a36Sopenharmony_ci		return -ENODEV;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (uas_switch_interface(udev, intf))
100462306a36Sopenharmony_ci		return -ENODEV;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	shost = scsi_host_alloc(&uas_host_template,
100762306a36Sopenharmony_ci				sizeof(struct uas_dev_info));
100862306a36Sopenharmony_ci	if (!shost)
100962306a36Sopenharmony_ci		goto set_alt0;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	shost->max_cmd_len = 16 + 252;
101262306a36Sopenharmony_ci	shost->max_id = 1;
101362306a36Sopenharmony_ci	shost->max_lun = 256;
101462306a36Sopenharmony_ci	shost->max_channel = 0;
101562306a36Sopenharmony_ci	shost->sg_tablesize = udev->bus->sg_tablesize;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	devinfo = (struct uas_dev_info *)shost->hostdata;
101862306a36Sopenharmony_ci	devinfo->intf = intf;
101962306a36Sopenharmony_ci	devinfo->udev = udev;
102062306a36Sopenharmony_ci	devinfo->resetting = 0;
102162306a36Sopenharmony_ci	devinfo->shutdown = 0;
102262306a36Sopenharmony_ci	devinfo->flags = dev_flags;
102362306a36Sopenharmony_ci	init_usb_anchor(&devinfo->cmd_urbs);
102462306a36Sopenharmony_ci	init_usb_anchor(&devinfo->sense_urbs);
102562306a36Sopenharmony_ci	init_usb_anchor(&devinfo->data_urbs);
102662306a36Sopenharmony_ci	spin_lock_init(&devinfo->lock);
102762306a36Sopenharmony_ci	INIT_WORK(&devinfo->work, uas_do_work);
102862306a36Sopenharmony_ci	INIT_WORK(&devinfo->scan_work, uas_scan_work);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	result = uas_configure_endpoints(devinfo);
103162306a36Sopenharmony_ci	if (result)
103262306a36Sopenharmony_ci		goto set_alt0;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/*
103562306a36Sopenharmony_ci	 * 1 tag is reserved for untagged commands +
103662306a36Sopenharmony_ci	 * 1 tag to avoid off by one errors in some bridge firmwares
103762306a36Sopenharmony_ci	 */
103862306a36Sopenharmony_ci	shost->can_queue = devinfo->qdepth - 2;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	usb_set_intfdata(intf, shost);
104162306a36Sopenharmony_ci	result = scsi_add_host(shost, &intf->dev);
104262306a36Sopenharmony_ci	if (result)
104362306a36Sopenharmony_ci		goto free_streams;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/* Submit the delayed_work for SCSI-device scanning */
104662306a36Sopenharmony_ci	schedule_work(&devinfo->scan_work);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	return result;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cifree_streams:
105162306a36Sopenharmony_ci	uas_free_streams(devinfo);
105262306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
105362306a36Sopenharmony_ciset_alt0:
105462306a36Sopenharmony_ci	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
105562306a36Sopenharmony_ci	if (shost)
105662306a36Sopenharmony_ci		scsi_host_put(shost);
105762306a36Sopenharmony_ci	return result;
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int uas_cmnd_list_empty(struct uas_dev_info *devinfo)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	unsigned long flags;
106362306a36Sopenharmony_ci	int i, r = 1;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	for (i = 0; i < devinfo->qdepth; i++) {
106862306a36Sopenharmony_ci		if (devinfo->cmnd[i]) {
106962306a36Sopenharmony_ci			r = 0; /* Not empty */
107062306a36Sopenharmony_ci			break;
107162306a36Sopenharmony_ci		}
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return r;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/*
108062306a36Sopenharmony_ci * Wait for any pending cmnds to complete, on usb-2 sense_urbs may temporarily
108162306a36Sopenharmony_ci * get empty while there still is more work to do due to sense-urbs completing
108262306a36Sopenharmony_ci * with a READ/WRITE_READY iu code, so keep waiting until the list gets empty.
108362306a36Sopenharmony_ci */
108462306a36Sopenharmony_cistatic int uas_wait_for_pending_cmnds(struct uas_dev_info *devinfo)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	unsigned long start_time;
108762306a36Sopenharmony_ci	int r;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	start_time = jiffies;
109062306a36Sopenharmony_ci	do {
109162306a36Sopenharmony_ci		flush_work(&devinfo->work);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		r = usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000);
109462306a36Sopenharmony_ci		if (r == 0)
109562306a36Sopenharmony_ci			return -ETIME;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		r = usb_wait_anchor_empty_timeout(&devinfo->data_urbs, 500);
109862306a36Sopenharmony_ci		if (r == 0)
109962306a36Sopenharmony_ci			return -ETIME;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		if (time_after(jiffies, start_time + 5 * HZ))
110262306a36Sopenharmony_ci			return -ETIME;
110362306a36Sopenharmony_ci	} while (!uas_cmnd_list_empty(devinfo));
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	return 0;
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_cistatic int uas_pre_reset(struct usb_interface *intf)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(intf);
111162306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
111262306a36Sopenharmony_ci	unsigned long flags;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (devinfo->shutdown)
111562306a36Sopenharmony_ci		return 0;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	/* Block new requests */
111862306a36Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, flags);
111962306a36Sopenharmony_ci	scsi_block_requests(shost);
112062306a36Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, flags);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (uas_wait_for_pending_cmnds(devinfo) != 0) {
112362306a36Sopenharmony_ci		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
112462306a36Sopenharmony_ci		scsi_unblock_requests(shost);
112562306a36Sopenharmony_ci		return 1;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	uas_free_streams(devinfo);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	return 0;
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic int uas_post_reset(struct usb_interface *intf)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(intf);
113662306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
113762306a36Sopenharmony_ci	unsigned long flags;
113862306a36Sopenharmony_ci	int err;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (devinfo->shutdown)
114162306a36Sopenharmony_ci		return 0;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	err = uas_configure_endpoints(devinfo);
114462306a36Sopenharmony_ci	if (err && err != -ENODEV)
114562306a36Sopenharmony_ci		shost_printk(KERN_ERR, shost,
114662306a36Sopenharmony_ci			     "%s: alloc streams error %d after reset",
114762306a36Sopenharmony_ci			     __func__, err);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	/* we must unblock the host in every case lest we deadlock */
115062306a36Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, flags);
115162306a36Sopenharmony_ci	scsi_report_bus_reset(shost, 0);
115262306a36Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, flags);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	scsi_unblock_requests(shost);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return err ? 1 : 0;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic int uas_suspend(struct usb_interface *intf, pm_message_t message)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(intf);
116262306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (uas_wait_for_pending_cmnds(devinfo) != 0) {
116562306a36Sopenharmony_ci		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
116662306a36Sopenharmony_ci		return -ETIME;
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	return 0;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic int uas_resume(struct usb_interface *intf)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	return 0;
117562306a36Sopenharmony_ci}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_cistatic int uas_reset_resume(struct usb_interface *intf)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(intf);
118062306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
118162306a36Sopenharmony_ci	unsigned long flags;
118262306a36Sopenharmony_ci	int err;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	err = uas_configure_endpoints(devinfo);
118562306a36Sopenharmony_ci	if (err) {
118662306a36Sopenharmony_ci		shost_printk(KERN_ERR, shost,
118762306a36Sopenharmony_ci			     "%s: alloc streams error %d after reset",
118862306a36Sopenharmony_ci			     __func__, err);
118962306a36Sopenharmony_ci		return -EIO;
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, flags);
119362306a36Sopenharmony_ci	scsi_report_bus_reset(shost, 0);
119462306a36Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, flags);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return 0;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic void uas_disconnect(struct usb_interface *intf)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(intf);
120262306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
120362306a36Sopenharmony_ci	unsigned long flags;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	spin_lock_irqsave(&devinfo->lock, flags);
120662306a36Sopenharmony_ci	devinfo->resetting = 1;
120762306a36Sopenharmony_ci	spin_unlock_irqrestore(&devinfo->lock, flags);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	cancel_work_sync(&devinfo->work);
121062306a36Sopenharmony_ci	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
121162306a36Sopenharmony_ci	usb_kill_anchored_urbs(&devinfo->sense_urbs);
121262306a36Sopenharmony_ci	usb_kill_anchored_urbs(&devinfo->data_urbs);
121362306a36Sopenharmony_ci	uas_zap_pending(devinfo, DID_NO_CONNECT);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	/*
121662306a36Sopenharmony_ci	 * Prevent SCSI scanning (if it hasn't started yet)
121762306a36Sopenharmony_ci	 * or wait for the SCSI-scanning routine to stop.
121862306a36Sopenharmony_ci	 */
121962306a36Sopenharmony_ci	cancel_work_sync(&devinfo->scan_work);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	scsi_remove_host(shost);
122262306a36Sopenharmony_ci	uas_free_streams(devinfo);
122362306a36Sopenharmony_ci	scsi_host_put(shost);
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci/*
122762306a36Sopenharmony_ci * Put the device back in usb-storage mode on shutdown, as some BIOS-es
122862306a36Sopenharmony_ci * hang on reboot when the device is still in uas mode. Note the reset is
122962306a36Sopenharmony_ci * necessary as some devices won't revert to usb-storage mode without it.
123062306a36Sopenharmony_ci */
123162306a36Sopenharmony_cistatic void uas_shutdown(struct device *dev)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);
123462306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(intf);
123562306a36Sopenharmony_ci	struct Scsi_Host *shost = usb_get_intfdata(intf);
123662306a36Sopenharmony_ci	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (system_state != SYSTEM_RESTART)
123962306a36Sopenharmony_ci		return;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	devinfo->shutdown = 1;
124262306a36Sopenharmony_ci	uas_free_streams(devinfo);
124362306a36Sopenharmony_ci	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
124462306a36Sopenharmony_ci	usb_reset_device(udev);
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic struct usb_driver uas_driver = {
124862306a36Sopenharmony_ci	.name = "uas",
124962306a36Sopenharmony_ci	.probe = uas_probe,
125062306a36Sopenharmony_ci	.disconnect = uas_disconnect,
125162306a36Sopenharmony_ci	.pre_reset = uas_pre_reset,
125262306a36Sopenharmony_ci	.post_reset = uas_post_reset,
125362306a36Sopenharmony_ci	.suspend = uas_suspend,
125462306a36Sopenharmony_ci	.resume = uas_resume,
125562306a36Sopenharmony_ci	.reset_resume = uas_reset_resume,
125662306a36Sopenharmony_ci	.drvwrap.driver.shutdown = uas_shutdown,
125762306a36Sopenharmony_ci	.id_table = uas_usb_ids,
125862306a36Sopenharmony_ci};
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic int __init uas_init(void)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	int rv;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	workqueue = alloc_workqueue("uas", WQ_MEM_RECLAIM, 0);
126562306a36Sopenharmony_ci	if (!workqueue)
126662306a36Sopenharmony_ci		return -ENOMEM;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	rv = usb_register(&uas_driver);
126962306a36Sopenharmony_ci	if (rv) {
127062306a36Sopenharmony_ci		destroy_workqueue(workqueue);
127162306a36Sopenharmony_ci		return -ENOMEM;
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	return 0;
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic void __exit uas_exit(void)
127862306a36Sopenharmony_ci{
127962306a36Sopenharmony_ci	usb_deregister(&uas_driver);
128062306a36Sopenharmony_ci	destroy_workqueue(workqueue);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cimodule_init(uas_init);
128462306a36Sopenharmony_cimodule_exit(uas_exit);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
128762306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE);
128862306a36Sopenharmony_ciMODULE_AUTHOR(
128962306a36Sopenharmony_ci	"Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp");
1290