uas.c 34.7 KB
Newer Older
Matthew Wilcox's avatar
Matthew Wilcox committed
1 2 3 4
/*
 * USB Attached SCSI
 * Note that this is not the same as the USB Mass Storage driver
 *
5
 * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013
Matthew Wilcox's avatar
Matthew Wilcox committed
6 7 8 9 10 11 12 13 14
 * Copyright Matthew Wilcox for Intel Corp, 2010
 * Copyright Sarah Sharp for Intel Corp, 2010
 *
 * Distributed under the terms of the GNU GPL, version two.
 */

#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/types.h>
15
#include <linux/module.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
16
#include <linux/usb.h>
17
#include <linux/usb_usual.h>
18
#include <linux/usb/hcd.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
19
#include <linux/usb/storage.h>
20
#include <linux/usb/uas.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
21 22

#include <scsi/scsi.h>
23
#include <scsi/scsi_eh.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
24 25 26 27 28 29
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>

30 31
#include "uas-detect.h"

Matthew Wilcox's avatar
Matthew Wilcox committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*
 * The r00-r01c specs define this version of the SENSE IU data structure.
 * It's still in use by several different firmware releases.
 */
struct sense_iu_old {
	__u8 iu_id;
	__u8 rsvd1;
	__be16 tag;
	__be16 len;
	__u8 status;
	__u8 service_response;
	__u8 sense[SCSI_SENSE_BUFFERSIZE];
};

struct uas_dev_info {
	struct usb_interface *intf;
	struct usb_device *udev;
49
	struct usb_anchor cmd_urbs;
50 51
	struct usb_anchor sense_urbs;
	struct usb_anchor data_urbs;
52
	int qdepth, resetting;
53
	struct response_iu response;
Matthew Wilcox's avatar
Matthew Wilcox committed
54 55 56
	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
	unsigned use_streams:1;
	unsigned uas_sense_old:1;
57
	unsigned running_task:1;
Hans de Goede's avatar
Hans de Goede committed
58
	unsigned shutdown:1;
59
	struct scsi_cmnd *cmnd;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
60
	spinlock_t lock;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
61
	struct work_struct work;
62
	struct list_head inflight_list;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
63
	struct list_head dead_list;
Matthew Wilcox's avatar
Matthew Wilcox committed
64 65 66
};

enum {
67
	SUBMIT_STATUS_URB	= (1 << 1),
Matthew Wilcox's avatar
Matthew Wilcox committed
68 69 70 71 72 73
	ALLOC_DATA_IN_URB	= (1 << 2),
	SUBMIT_DATA_IN_URB	= (1 << 3),
	ALLOC_DATA_OUT_URB	= (1 << 4),
	SUBMIT_DATA_OUT_URB	= (1 << 5),
	ALLOC_CMD_URB		= (1 << 6),
	SUBMIT_CMD_URB		= (1 << 7),
74 75 76 77
	COMMAND_INFLIGHT        = (1 << 8),
	DATA_IN_URB_INFLIGHT    = (1 << 9),
	DATA_OUT_URB_INFLIGHT   = (1 << 10),
	COMMAND_COMPLETED       = (1 << 11),
78
	COMMAND_ABORTED         = (1 << 12),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
79
	UNLINK_DATA_URBS        = (1 << 13),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
80
	IS_IN_WORK_LIST         = (1 << 14),
Matthew Wilcox's avatar
Matthew Wilcox committed
81 82 83 84 85 86 87 88 89
};

/* Overrides scsi_pointer */
struct uas_cmd_info {
	unsigned int state;
	unsigned int stream;
	struct urb *cmd_urb;
	struct urb *data_in_urb;
	struct urb *data_out_urb;
90
	struct list_head list;
Matthew Wilcox's avatar
Matthew Wilcox committed
91 92 93 94 95
};

/* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
				struct uas_dev_info *devinfo, gfp_t gfp);
96
static void uas_do_work(struct work_struct *work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
97
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
98
static void uas_free_streams(struct uas_dev_info *devinfo);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
99
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
Matthew Wilcox's avatar
Matthew Wilcox committed
100

101
/* Must be called with devinfo->lock held, will temporary unlock the lock */
102
static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
103 104
				 struct uas_cmd_info *cmdinfo,
				 unsigned long *lock_flags)
105
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
106 107 108 109 110 111
	/*
	 * The UNLINK_DATA_URBS flag makes sure uas_try_complete
	 * (called by urb completion) doesn't release cmdinfo
	 * underneath us.
	 */
	cmdinfo->state |= UNLINK_DATA_URBS;
112
	spin_unlock_irqrestore(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
113

114 115 116 117
	if (cmdinfo->data_in_urb)
		usb_unlink_urb(cmdinfo->data_in_urb);
	if (cmdinfo->data_out_urb)
		usb_unlink_urb(cmdinfo->data_out_urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
118

119
	spin_lock_irqsave(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
120
	cmdinfo->state &= ~UNLINK_DATA_URBS;
121 122
}

Matthew Wilcox's avatar
Matthew Wilcox committed
123 124
static void uas_do_work(struct work_struct *work)
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
125 126
	struct uas_dev_info *devinfo =
		container_of(work, struct uas_dev_info, work);
Matthew Wilcox's avatar
Matthew Wilcox committed
127
	struct uas_cmd_info *cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
128
	unsigned long flags;
129
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
130

Gerd Hoffmann's avatar
Gerd Hoffmann committed
131
	spin_lock_irqsave(&devinfo->lock, flags);
132
	list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) {
Matthew Wilcox's avatar
Matthew Wilcox committed
133
		struct scsi_pointer *scp = (void *)cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
134 135
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
136 137 138 139

		if (!(cmdinfo->state & IS_IN_WORK_LIST))
			continue;

140
		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
141
		if (!err)
Gerd Hoffmann's avatar
Gerd Hoffmann committed
142
			cmdinfo->state &= ~IS_IN_WORK_LIST;
143
		else
Gerd Hoffmann's avatar
Gerd Hoffmann committed
144
			schedule_work(&devinfo->work);
Matthew Wilcox's avatar
Matthew Wilcox committed
145
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
146
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
147 148
}

149
static void uas_mark_cmd_dead(struct uas_dev_info *devinfo,
150 151
			      struct uas_cmd_info *cmdinfo,
			      int result, const char *caller)
152 153 154 155 156 157 158 159 160
{
	struct scsi_pointer *scp = (void *)cmdinfo;
	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);

	uas_log_cmd_state(cmnd, caller);
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
	cmdinfo->state |= COMMAND_ABORTED;
	cmdinfo->state &= ~IS_IN_WORK_LIST;
161
	cmnd->result = result << 16;
162
	list_move_tail(&cmdinfo->list, &devinfo->dead_list);
163 164
}

165 166
static void uas_abort_inflight(struct uas_dev_info *devinfo, int result,
			       const char *caller)
Gerd Hoffmann's avatar
Gerd Hoffmann committed
167 168 169 170 171 172
{
	struct uas_cmd_info *cmdinfo;
	struct uas_cmd_info *temp;
	unsigned long flags;

	spin_lock_irqsave(&devinfo->lock, flags);
173
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->inflight_list, list)
174
		uas_mark_cmd_dead(devinfo, cmdinfo, result, caller);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
175 176 177
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
178 179 180 181 182 183
static void uas_add_work(struct uas_cmd_info *cmdinfo)
{
	struct scsi_pointer *scp = (void *)cmdinfo;
	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
	struct uas_dev_info *devinfo = cmnd->device->hostdata;

184
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
185 186 187 188
	cmdinfo->state |= IS_IN_WORK_LIST;
	schedule_work(&devinfo->work);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
189 190 191 192 193 194 195
static void uas_zap_dead(struct uas_dev_info *devinfo)
{
	struct uas_cmd_info *cmdinfo;
	struct uas_cmd_info *temp;
	unsigned long flags;

	spin_lock_irqsave(&devinfo->lock, flags);
196
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, list) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
197 198 199 200
		struct scsi_pointer *scp = (void *)cmdinfo;
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
		uas_log_cmd_state(cmnd, __func__);
201
		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
202 203 204 205 206 207
		/* all urbs are killed, clear inflight bits */
		cmdinfo->state &= ~(COMMAND_INFLIGHT |
				    DATA_IN_URB_INFLIGHT |
				    DATA_OUT_URB_INFLIGHT);
		uas_try_complete(cmnd, __func__);
	}
208
	devinfo->running_task = 0;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
209 210 211
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
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;

	if (urb->actual_length > 16) {
		unsigned len = be16_to_cpup(&sense_iu->len);
		if (len + 16 != urb->actual_length) {
			int newlen = min(len + 16, urb->actual_length) - 16;
			if (newlen < 0)
				newlen = 0;
			sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
				"disagrees with IU sense data length %d, "
				"using %d bytes of sense data\n", __func__,
					urb->actual_length, len, newlen);
			len = newlen;
		}
		memcpy(cmnd->sense_buffer, sense_iu->sense, len);
	}

	cmnd->result = sense_iu->status;
}

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;

	if (urb->actual_length > 8) {
		unsigned len = be16_to_cpup(&sense_iu->len) - 2;
		if (len + 8 != urb->actual_length) {
			int newlen = min(len + 8, urb->actual_length) - 8;
			if (newlen < 0)
				newlen = 0;
			sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
				"disagrees with IU sense data length %d, "
				"using %d bytes of sense data\n", __func__,
					urb->actual_length, len, newlen);
			len = newlen;
		}
		memcpy(cmnd->sense_buffer, sense_iu->sense, len);
	}

	cmnd->result = sense_iu->status;
256 257 258 259 260 261 262
}

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:"
Gerd Hoffmann's avatar
Gerd Hoffmann committed
263
		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
264 265 266 267 268 269 270 271 272 273 274
		    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"   : "",
275
		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
276
		    (ci->state & COMMAND_ABORTED)       ? " abort" : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
277 278
		    (ci->state & UNLINK_DATA_URBS)      ? " unlink": "",
		    (ci->state & IS_IN_WORK_LIST)       ? " work"  : "");
279 280 281 282 283
}

static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
284
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
285

286
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
287 288
	if (cmdinfo->state & (COMMAND_INFLIGHT |
			      DATA_IN_URB_INFLIGHT |
Gerd Hoffmann's avatar
Gerd Hoffmann committed
289 290
			      DATA_OUT_URB_INFLIGHT |
			      UNLINK_DATA_URBS))
291
		return -EBUSY;
292
	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
293 294 295
	cmdinfo->state |= COMMAND_COMPLETED;
	usb_free_urb(cmdinfo->data_in_urb);
	usb_free_urb(cmdinfo->data_out_urb);
296
	if (cmdinfo->state & COMMAND_ABORTED)
Gerd Hoffmann's avatar
Gerd Hoffmann committed
297
		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
298
	list_del(&cmdinfo->list);
299
	cmnd->scsi_done(cmnd);
300
	return 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
301 302 303
}

static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
304
			  unsigned direction)
Matthew Wilcox's avatar
Matthew Wilcox committed
305 306 307 308
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
	int err;

309
	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
310 311
	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
	if (err) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
312
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
313 314 315 316 317 318
	}
}

static void uas_stat_cmplt(struct urb *urb)
{
	struct iu *iu = urb->transfer_buffer;
319
	struct Scsi_Host *shost = urb->context;
Hans de Goede's avatar
Hans de Goede committed
320
	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
Matthew Wilcox's avatar
Matthew Wilcox committed
321
	struct scsi_cmnd *cmnd;
322
	struct uas_cmd_info *cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
323
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
324 325 326
	u16 tag;

	if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
327 328 329 330 331 332 333
		if (urb->status == -ENOENT) {
			dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
				urb->stream_id);
		} else {
			dev_err(&urb->dev->dev, "stat urb: status %d\n",
				urb->status);
		}
334
		usb_free_urb(urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
335 336 337
		return;
	}

338 339 340 341 342
	if (devinfo->resetting) {
		usb_free_urb(urb);
		return;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
343
	spin_lock_irqsave(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
344
	tag = be16_to_cpup(&iu->tag) - 1;
345 346
	if (tag == 0)
		cmnd = devinfo->cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
347
	else
348
		cmnd = scsi_host_find_tag(shost, tag - 1);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
349

350
	if (!cmnd) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
351
		if (iu->iu_id == IU_ID_RESPONSE) {
352 353 354
			if (!devinfo->running_task)
				dev_warn(&urb->dev->dev,
				    "stat urb: recv unexpected response iu\n");
Gerd Hoffmann's avatar
Gerd Hoffmann committed
355 356
			/* store results for uas_eh_task_mgmt() */
			memcpy(&devinfo->response, iu, sizeof(devinfo->response));
357
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
358 359 360
		usb_free_urb(urb);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return;
361
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
362

Gerd Hoffmann's avatar
Gerd Hoffmann committed
363
	cmdinfo = (void *)&cmnd->SCp;
Matthew Wilcox's avatar
Matthew Wilcox committed
364 365
	switch (iu->iu_id) {
	case IU_ID_STATUS:
366 367 368
		if (devinfo->cmnd == cmnd)
			devinfo->cmnd = NULL;

Matthew Wilcox's avatar
Matthew Wilcox committed
369 370 371 372 373 374
		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);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
375 376
		if (cmnd->result != 0) {
			/* cancel data transfers on error */
377
			uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
378
		}
379 380
		cmdinfo->state &= ~COMMAND_INFLIGHT;
		uas_try_complete(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
381 382
		break;
	case IU_ID_READ_READY:
383 384 385 386 387
		if (!cmdinfo->data_in_urb ||
				(cmdinfo->state & DATA_IN_URB_INFLIGHT)) {
			scmd_printk(KERN_ERR, cmnd, "unexpected read rdy\n");
			break;
		}
Matthew Wilcox's avatar
Matthew Wilcox committed
388 389 390
		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
		break;
	case IU_ID_WRITE_READY:
391 392 393 394 395
		if (!cmdinfo->data_out_urb ||
				(cmdinfo->state & DATA_OUT_URB_INFLIGHT)) {
			scmd_printk(KERN_ERR, cmnd, "unexpected write rdy\n");
			break;
		}
Matthew Wilcox's avatar
Matthew Wilcox committed
396 397 398 399 400 401
		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
		break;
	default:
		scmd_printk(KERN_ERR, cmnd,
			"Bogus IU (%d) received on status pipe\n", iu->iu_id);
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
402
	usb_free_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
403
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
404 405
}

406
static void uas_data_cmplt(struct urb *urb)
Matthew Wilcox's avatar
Matthew Wilcox committed
407
{
408 409
	struct scsi_cmnd *cmnd = urb->context;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
410
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
411
	struct scsi_data_buffer *sdb = NULL;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
412
	unsigned long flags;
413

Gerd Hoffmann's avatar
Gerd Hoffmann committed
414
	spin_lock_irqsave(&devinfo->lock, flags);
415 416 417 418 419 420 421
	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;
	}
422 423 424
	if (sdb == NULL) {
		WARN_ON_ONCE(1);
	} else if (urb->status) {
Hans de Goede's avatar
Hans de Goede committed
425 426 427 428 429 430
		if (urb->status != -ECONNRESET) {
			uas_log_cmd_state(cmnd, __func__);
			scmd_printk(KERN_ERR, cmnd,
				"data cmplt err %d stream %d\n",
				urb->status, urb->stream_id);
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
431 432 433 434 435
		/* error: no data transfered */
		sdb->resid = sdb->length;
	} else {
		sdb->resid = sdb->length - urb->actual_length;
	}
436
	uas_try_complete(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
437
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
438 439
}

Hans de Goede's avatar
Hans de Goede committed
440 441 442 443 444 445 446 447 448 449 450
static void uas_cmd_cmplt(struct urb *urb)
{
	struct scsi_cmnd *cmnd = urb->context;

	if (urb->status) {
		uas_log_cmd_state(cmnd, __func__);
		scmd_printk(KERN_ERR, cmnd, "cmd cmplt err %d\n", urb->status);
	}
	usb_free_urb(urb);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
451
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
452 453 454
				      unsigned int pipe, u16 stream_id,
				      struct scsi_cmnd *cmnd,
				      enum dma_data_direction dir)
Matthew Wilcox's avatar
Matthew Wilcox committed
455 456 457
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
458 459
	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
		? scsi_in(cmnd) : scsi_out(cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
460 461 462

	if (!urb)
		goto out;
463 464
	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
			  uas_data_cmplt, cmnd);
465
	urb->stream_id = stream_id;
Matthew Wilcox's avatar
Matthew Wilcox committed
466 467 468 469 470 471 472
	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
	urb->sg = sdb->table.sgl;
 out:
	return urb;
}

static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
Gerd Hoffmann's avatar
Gerd Hoffmann committed
473
				       struct Scsi_Host *shost, u16 stream_id)
Matthew Wilcox's avatar
Matthew Wilcox committed
474 475 476 477 478 479 480 481
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct sense_iu *iu;

	if (!urb)
		goto out;

482
	iu = kzalloc(sizeof(*iu), gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
483 484 485 486
	if (!iu)
		goto free;

	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
487
						uas_stat_cmplt, shost);
Matthew Wilcox's avatar
Matthew Wilcox committed
488 489 490 491 492 493 494 495 496 497
	urb->stream_id = stream_id;
	urb->transfer_flags |= URB_FREE_BUFFER;
 out:
	return urb;
 free:
	usb_free_urb(urb);
	return NULL;
}

static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
498
					struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512
{
	struct usb_device *udev = devinfo->udev;
	struct scsi_device *sdev = cmnd->device;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct command_iu *iu;
	int len;

	if (!urb)
		goto out;

	len = cmnd->cmd_len - 16;
	if (len < 0)
		len = 0;
	len = ALIGN(len, 4);
513
	iu = kzalloc(sizeof(*iu) + len, gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
514 515 516 517
	if (!iu)
		goto free;

	iu->iu_id = IU_ID_COMMAND;
518
	if (blk_rq_tagged(cmnd->request))
519
		iu->tag = cpu_to_be16(cmnd->request->tag + 2);
520 521
	else
		iu->tag = cpu_to_be16(1);
522
	iu->prio_attr = UAS_SIMPLE_TAG;
Matthew Wilcox's avatar
Matthew Wilcox committed
523 524 525 526 527
	iu->len = len;
	int_to_scsilun(sdev->lun, &iu->lun);
	memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);

	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len,
Hans de Goede's avatar
Hans de Goede committed
528
							uas_cmd_cmplt, cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
529 530 531 532 533 534 535 536
	urb->transfer_flags |= URB_FREE_BUFFER;
 out:
	return urb;
 free:
	usb_free_urb(urb);
	return NULL;
}

537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
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),
Hans de Goede's avatar
Hans de Goede committed
568
			  uas_cmd_cmplt, cmnd);
569 570
	urb->transfer_flags |= URB_FREE_BUFFER;

571
	usb_anchor_urb(urb, &devinfo->cmd_urbs);
572
	err = usb_submit_urb(urb, gfp);
573 574
	if (err) {
		usb_unanchor_urb(urb);
Hans de Goede's avatar
Hans de Goede committed
575 576
		uas_log_cmd_state(cmnd, __func__);
		scmd_printk(KERN_ERR, cmnd, "task submission err %d\n", err);
577
		goto err;
578
	}
579 580 581 582 583 584 585 586

	return 0;

err:
	usb_free_urb(urb);
	return err;
}

Matthew Wilcox's avatar
Matthew Wilcox committed
587 588 589 590 591 592
/*
 * 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.
 */

Hans de Goede's avatar
Hans de Goede committed
593
static struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd,
594
					gfp_t gfp, unsigned int stream)
Matthew Wilcox's avatar
Matthew Wilcox committed
595
{
Hans de Goede's avatar
Hans de Goede committed
596
	struct Scsi_Host *shost = cmnd->device->host;
Hans de Goede's avatar
Hans de Goede committed
597
	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
598
	struct urb *urb;
Hans de Goede's avatar
Hans de Goede committed
599
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
600

Gerd Hoffmann's avatar
Gerd Hoffmann committed
601 602
	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
	if (!urb)
603
		return NULL;
604
	usb_anchor_urb(urb, &devinfo->sense_urbs);
Hans de Goede's avatar
Hans de Goede committed
605 606
	err = usb_submit_urb(urb, gfp);
	if (err) {
607
		usb_unanchor_urb(urb);
Hans de Goede's avatar
Hans de Goede committed
608
		uas_log_cmd_state(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
609
		shost_printk(KERN_INFO, shost,
Hans de Goede's avatar
Hans de Goede committed
610 611
			     "sense urb submission error %d stream %d\n",
			     err, stream);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
612
		usb_free_urb(urb);
613
		return NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
614
	}
615
	return urb;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
616 617 618 619 620 621
}

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;
622
	struct urb *urb;
Hans de Goede's avatar
Hans de Goede committed
623
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
624

625
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
626
	if (cmdinfo->state & SUBMIT_STATUS_URB) {
Hans de Goede's avatar
Hans de Goede committed
627
		urb = uas_submit_sense_urb(cmnd, gfp, cmdinfo->stream);
628 629
		if (!urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
630
		cmdinfo->state &= ~SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
631 632 633 634
	}

	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
635
					devinfo->data_in_pipe, cmdinfo->stream,
636
					cmnd, DMA_FROM_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
637 638 639 640 641 642
		if (!cmdinfo->data_in_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
643
		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
Hans de Goede's avatar
Hans de Goede committed
644 645
		err = usb_submit_urb(cmdinfo->data_in_urb, gfp);
		if (err) {
646
			usb_unanchor_urb(cmdinfo->data_in_urb);
Hans de Goede's avatar
Hans de Goede committed
647
			uas_log_cmd_state(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
648
			scmd_printk(KERN_INFO, cmnd,
Hans de Goede's avatar
Hans de Goede committed
649 650
				"data in urb submission error %d stream %d\n",
				err, cmdinfo->data_in_urb->stream_id);
Matthew Wilcox's avatar
Matthew Wilcox committed
651 652 653
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
654
		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
655 656 657 658
	}

	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
659
					devinfo->data_out_pipe, cmdinfo->stream,
660
					cmnd, DMA_TO_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
661 662 663 664 665 666
		if (!cmdinfo->data_out_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
667
		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
Hans de Goede's avatar
Hans de Goede committed
668 669
		err = usb_submit_urb(cmdinfo->data_out_urb, gfp);
		if (err) {
670
			usb_unanchor_urb(cmdinfo->data_out_urb);
Hans de Goede's avatar
Hans de Goede committed
671
			uas_log_cmd_state(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
672
			scmd_printk(KERN_INFO, cmnd,
Hans de Goede's avatar
Hans de Goede committed
673 674
				"data out urb submission error %d stream %d\n",
				err, cmdinfo->data_out_urb->stream_id);
Matthew Wilcox's avatar
Matthew Wilcox committed
675 676 677
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
678
		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
679 680 681
	}

	if (cmdinfo->state & ALLOC_CMD_URB) {
682
		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
683 684 685 686 687 688
		if (!cmdinfo->cmd_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_CMD_URB;
	}

	if (cmdinfo->state & SUBMIT_CMD_URB) {
689
		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
Hans de Goede's avatar
Hans de Goede committed
690 691
		err = usb_submit_urb(cmdinfo->cmd_urb, gfp);
		if (err) {
692
			usb_unanchor_urb(cmdinfo->cmd_urb);
Hans de Goede's avatar
Hans de Goede committed
693
			uas_log_cmd_state(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
694
			scmd_printk(KERN_INFO, cmnd,
Hans de Goede's avatar
Hans de Goede committed
695
				    "cmd urb submission error %d\n", err);
Matthew Wilcox's avatar
Matthew Wilcox committed
696 697
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
698
		cmdinfo->cmd_urb = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
699
		cmdinfo->state &= ~SUBMIT_CMD_URB;
700
		cmdinfo->state |= COMMAND_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
701 702 703 704 705
	}

	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
706
static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
Matthew Wilcox's avatar
Matthew Wilcox committed
707 708 709 710 711
					void (*done)(struct scsi_cmnd *))
{
	struct scsi_device *sdev = cmnd->device;
	struct uas_dev_info *devinfo = sdev->hostdata;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
712
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
713 714 715 716
	int err;

	BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));

717 718
	spin_lock_irqsave(&devinfo->lock, flags);

719 720 721
	if (devinfo->resetting) {
		cmnd->result = DID_ERROR << 16;
		cmnd->scsi_done(cmnd);
722
		spin_unlock_irqrestore(&devinfo->lock, flags);
723 724 725
		return 0;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
726 727
	if (devinfo->cmnd) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
728
		return SCSI_MLQUEUE_DEVICE_BUSY;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
729
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
730

731 732
	memset(cmdinfo, 0, sizeof(*cmdinfo));

Matthew Wilcox's avatar
Matthew Wilcox committed
733
	if (blk_rq_tagged(cmnd->request)) {
734
		cmdinfo->stream = cmnd->request->tag + 2;
Matthew Wilcox's avatar
Matthew Wilcox committed
735
	} else {
736
		devinfo->cmnd = cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
737 738 739 740 741
		cmdinfo->stream = 1;
	}

	cmnd->scsi_done = done;

Gerd Hoffmann's avatar
Gerd Hoffmann committed
742
	cmdinfo->state = SUBMIT_STATUS_URB |
Matthew Wilcox's avatar
Matthew Wilcox committed
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
			ALLOC_CMD_URB | SUBMIT_CMD_URB;

	switch (cmnd->sc_data_direction) {
	case DMA_FROM_DEVICE:
		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
		break;
	case DMA_BIDIRECTIONAL:
		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
	case DMA_TO_DEVICE:
		cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
	case DMA_NONE:
		break;
	}

	if (!devinfo->use_streams) {
758
		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
Matthew Wilcox's avatar
Matthew Wilcox committed
759 760 761 762 763 764
		cmdinfo->stream = 0;
	}

	err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
	if (err) {
		/* If we did nothing, give up now */
765
		if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
766
			spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
767 768
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
769
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
770 771
	}

772
	list_add_tail(&cmdinfo->list, &devinfo->inflight_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
773
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
774 775 776
	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
777 778
static DEF_SCSI_QCMD(uas_queuecommand)

779 780
static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
			    const char *fname, u8 function)
Matthew Wilcox's avatar
Matthew Wilcox committed
781
{
782
	struct Scsi_Host *shost = cmnd->device->host;
Hans de Goede's avatar
Hans de Goede committed
783
	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
784
	u16 tag = devinfo->qdepth;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
785
	unsigned long flags;
786
	struct urb *sense_urb;
787
	int result = SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
788

Gerd Hoffmann's avatar
Gerd Hoffmann committed
789
	spin_lock_irqsave(&devinfo->lock, flags);
790

791 792 793 794 795
	if (devinfo->resetting) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return FAILED;
	}

796 797 798 799 800 801 802 803 804
	if (devinfo->running_task) {
		shost_printk(KERN_INFO, shost,
			     "%s: %s: error already running a task\n",
			     __func__, fname);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return FAILED;
	}

	devinfo->running_task = 1;
805
	memset(&devinfo->response, 0, sizeof(devinfo->response));
806
	sense_urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC,
807
					 devinfo->use_streams ? tag : 0);
808
	if (!sense_urb) {
809 810 811
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit sense urb failed\n",
			     __func__, fname);
812
		devinfo->running_task = 0;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
813
		spin_unlock_irqrestore(&devinfo->lock, flags);
814 815
		return FAILED;
	}
816
	if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
817 818 819
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit task mgmt urb failed\n",
			     __func__, fname);
820
		devinfo->running_task = 0;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
821
		spin_unlock_irqrestore(&devinfo->lock, flags);
822
		usb_kill_urb(sense_urb);
823 824
		return FAILED;
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
825 826 827
	spin_unlock_irqrestore(&devinfo->lock, flags);

	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
828 829 830 831 832 833
		/*
		 * Note we deliberately do not clear running_task here. If we
		 * allow new tasks to be submitted, there is no way to figure
		 * out if a received response_iu is for the failed task or for
		 * the new one. A bus-reset will eventually clear running_task.
		 */
834 835 836 837
		shost_printk(KERN_INFO, shost,
			     "%s: %s timed out\n", __func__, fname);
		return FAILED;
	}
838 839 840

	spin_lock_irqsave(&devinfo->lock, flags);
	devinfo->running_task = 0;
841 842 843 844
	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);
845 846
		result = FAILED;
	} else if (devinfo->response.response_code != RC_TMF_COMPLETE) {
847 848 849
		shost_printk(KERN_INFO, shost,
			     "%s: %s failed (rc 0x%x)\n", __func__,
			     fname, devinfo->response.response_code);
850
		result = FAILED;
851
	}
852 853 854
	spin_unlock_irqrestore(&devinfo->lock, flags);

	return result;
Matthew Wilcox's avatar
Matthew Wilcox committed
855 856
}

857
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
858
{
859
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
860 861
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	unsigned long flags;
862
	int ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
863

Gerd Hoffmann's avatar
Gerd Hoffmann committed
864
	spin_lock_irqsave(&devinfo->lock, flags);
865 866 867 868 869 870

	if (devinfo->resetting) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return FAILED;
	}

871
	uas_mark_cmd_dead(devinfo, cmdinfo, DID_ABORT, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
872 873 874 875
	if (cmdinfo->state & COMMAND_INFLIGHT) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
	} else {
876
		uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
877 878 879 880
		uas_try_complete(cmnd, __func__);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = SUCCESS;
	}
881
	return ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
882 883
}

884
static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
885
{
886 887 888
	sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
	return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
				TMF_LOGICAL_UNIT_RESET);
Matthew Wilcox's avatar