uas.c 30 KB
Newer Older
Matthew Wilcox's avatar
Matthew Wilcox committed
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * USB Attached SCSI
 * Note that this is not the same as the USB Mass Storage driver
 *
 * 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>
14
#include <linux/module.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
15
#include <linux/usb.h>
16
#include <linux/usb/hcd.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
17
#include <linux/usb/storage.h>
18
#include <linux/usb/uas.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

#include <scsi/scsi.h>
#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>

/*
 * 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;
44
	struct usb_anchor cmd_urbs;
45
46
	struct usb_anchor sense_urbs;
	struct usb_anchor data_urbs;
47
48
	int qdepth, resetting;
	struct response_ui response;
Matthew Wilcox's avatar
Matthew Wilcox committed
49
50
51
	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
	unsigned use_streams:1;
	unsigned uas_sense_old:1;
52
	struct scsi_cmnd *cmnd;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
53
	spinlock_t lock;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
54
55
	struct work_struct work;
	struct list_head work_list;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
56
	struct list_head dead_list;
Matthew Wilcox's avatar
Matthew Wilcox committed
57
58
59
};

enum {
60
	SUBMIT_STATUS_URB	= (1 << 1),
Matthew Wilcox's avatar
Matthew Wilcox committed
61
62
63
64
65
66
	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),
67
68
69
70
	COMMAND_INFLIGHT        = (1 << 8),
	DATA_IN_URB_INFLIGHT    = (1 << 9),
	DATA_OUT_URB_INFLIGHT   = (1 << 10),
	COMMAND_COMPLETED       = (1 << 11),
71
	COMMAND_ABORTED         = (1 << 12),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
72
	UNLINK_DATA_URBS        = (1 << 13),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
73
	IS_IN_WORK_LIST         = (1 << 14),
Matthew Wilcox's avatar
Matthew Wilcox committed
74
75
76
77
78
79
80
81
82
};

/* 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;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
83
	struct list_head work;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
84
	struct list_head dead;
Matthew Wilcox's avatar
Matthew Wilcox committed
85
86
87
88
89
};

/* 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);
90
static void uas_do_work(struct work_struct *work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
91
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
92
93
static void uas_configure_endpoints(struct uas_dev_info *devinfo);
static void uas_free_streams(struct uas_dev_info *devinfo);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
94
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
Matthew Wilcox's avatar
Matthew Wilcox committed
95

96
/* Must be called with devinfo->lock held, will temporary unlock the lock */
97
static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
98
99
				 struct uas_cmd_info *cmdinfo,
				 unsigned long *lock_flags)
100
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
101
102
103
104
105
106
	/*
	 * 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;
107
	spin_unlock_irqrestore(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
108

109
110
111
112
	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
113

114
	spin_lock_irqsave(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
115
	cmdinfo->state &= ~UNLINK_DATA_URBS;
116
117
}

Matthew Wilcox's avatar
Matthew Wilcox committed
118
119
static void uas_do_work(struct work_struct *work)
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
120
121
	struct uas_dev_info *devinfo =
		container_of(work, struct uas_dev_info, work);
Matthew Wilcox's avatar
Matthew Wilcox committed
122
	struct uas_cmd_info *cmdinfo;
123
	struct uas_cmd_info *temp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
124
	unsigned long flags;
125
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
126

Gerd Hoffmann's avatar
Gerd Hoffmann committed
127
128
	spin_lock_irqsave(&devinfo->lock, flags);
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
Matthew Wilcox's avatar
Matthew Wilcox committed
129
		struct scsi_pointer *scp = (void *)cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
130
131
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
132
		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
133
		if (!err) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
134
			cmdinfo->state &= ~IS_IN_WORK_LIST;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
135
136
137
			list_del(&cmdinfo->work);
		} else {
			schedule_work(&devinfo->work);
138
		}
Matthew Wilcox's avatar
Matthew Wilcox committed
139
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
140
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
141
142
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
143
144
145
146
147
148
149
static void uas_abort_work(struct uas_dev_info *devinfo)
{
	struct uas_cmd_info *cmdinfo;
	struct uas_cmd_info *temp;
	unsigned long flags;

	spin_lock_irqsave(&devinfo->lock, flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
150
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
151
		struct scsi_pointer *scp = (void *)cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
152
153
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
154
		uas_log_cmd_state(cmnd, __func__);
155
		WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
156
157
158
		cmdinfo->state |= COMMAND_ABORTED;
		cmdinfo->state &= ~IS_IN_WORK_LIST;
		list_del(&cmdinfo->work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
159
		list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
160
161
162
163
	}
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
164
165
166
167
168
169
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;

170
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
171
172
173
174
175
	list_add_tail(&cmdinfo->work, &devinfo->work_list);
	cmdinfo->state |= IS_IN_WORK_LIST;
	schedule_work(&devinfo->work);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
176
177
178
179
180
181
182
183
184
185
186
187
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);
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, dead) {
		struct scsi_pointer *scp = (void *)cmdinfo;
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
		uas_log_cmd_state(cmnd, __func__);
188
		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
189
190
191
192
193
194
195
196
197
		/* all urbs are killed, clear inflight bits */
		cmdinfo->state &= ~(COMMAND_INFLIGHT |
				    DATA_IN_URB_INFLIGHT |
				    DATA_OUT_URB_INFLIGHT);
		uas_try_complete(cmnd, __func__);
	}
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
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;
242
243
244
245
246
247
248
}

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
249
		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
250
251
252
253
254
255
256
257
258
259
260
		    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"   : "",
261
		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
262
		    (ci->state & COMMAND_ABORTED)       ? " abort" : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
263
264
		    (ci->state & UNLINK_DATA_URBS)      ? " unlink": "",
		    (ci->state & IS_IN_WORK_LIST)       ? " work"  : "");
265
266
267
268
269
}

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
270
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
271

272
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
273
274
	if (cmdinfo->state & (COMMAND_INFLIGHT |
			      DATA_IN_URB_INFLIGHT |
Gerd Hoffmann's avatar
Gerd Hoffmann committed
275
276
			      DATA_OUT_URB_INFLIGHT |
			      UNLINK_DATA_URBS))
277
		return -EBUSY;
278
	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
279
280
281
	cmdinfo->state |= COMMAND_COMPLETED;
	usb_free_urb(cmdinfo->data_in_urb);
	usb_free_urb(cmdinfo->data_out_urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
282
283
284
	if (cmdinfo->state & COMMAND_ABORTED) {
		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
		cmnd->result = DID_ABORT << 16;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
285
		list_del(&cmdinfo->dead);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
286
	}
287
	cmnd->scsi_done(cmnd);
288
	return 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
289
290
291
}

static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
292
			  unsigned direction)
Matthew Wilcox's avatar
Matthew Wilcox committed
293
294
295
296
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
	int err;

297
	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
298
299
	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
	if (err) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
300
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
301
302
303
304
305
306
	}
}

static void uas_stat_cmplt(struct urb *urb)
{
	struct iu *iu = urb->transfer_buffer;
307
308
	struct Scsi_Host *shost = urb->context;
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
Matthew Wilcox's avatar
Matthew Wilcox committed
309
	struct scsi_cmnd *cmnd;
310
	struct uas_cmd_info *cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
311
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
312
313
314
	u16 tag;

	if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
315
316
317
318
319
320
321
		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);
		}
322
		usb_free_urb(urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
323
324
325
		return;
	}

326
327
328
329
330
	if (devinfo->resetting) {
		usb_free_urb(urb);
		return;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
331
	spin_lock_irqsave(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
332
	tag = be16_to_cpup(&iu->tag) - 1;
333
334
	if (tag == 0)
		cmnd = devinfo->cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
335
	else
336
		cmnd = scsi_host_find_tag(shost, tag - 1);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
337

338
	if (!cmnd) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
339
340
341
		if (iu->iu_id == IU_ID_RESPONSE) {
			/* store results for uas_eh_task_mgmt() */
			memcpy(&devinfo->response, iu, sizeof(devinfo->response));
342
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
343
344
345
		usb_free_urb(urb);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return;
346
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
347

Gerd Hoffmann's avatar
Gerd Hoffmann committed
348
	cmdinfo = (void *)&cmnd->SCp;
Matthew Wilcox's avatar
Matthew Wilcox committed
349
350
	switch (iu->iu_id) {
	case IU_ID_STATUS:
351
352
353
		if (devinfo->cmnd == cmnd)
			devinfo->cmnd = NULL;

Matthew Wilcox's avatar
Matthew Wilcox committed
354
355
356
357
358
359
		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
360
361
		if (cmnd->result != 0) {
			/* cancel data transfers on error */
362
			uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
363
		}
364
365
		cmdinfo->state &= ~COMMAND_INFLIGHT;
		uas_try_complete(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
366
367
368
369
370
371
372
373
374
375
376
		break;
	case IU_ID_READ_READY:
		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
		break;
	case IU_ID_WRITE_READY:
		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
377
	usb_free_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
378
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
379
380
}

381
static void uas_data_cmplt(struct urb *urb)
Matthew Wilcox's avatar
Matthew Wilcox committed
382
{
383
384
	struct scsi_cmnd *cmnd = urb->context;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
385
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
386
	struct scsi_data_buffer *sdb = NULL;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
387
	unsigned long flags;
388

Gerd Hoffmann's avatar
Gerd Hoffmann committed
389
	spin_lock_irqsave(&devinfo->lock, flags);
390
391
392
393
394
395
396
	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;
	}
397
398
399
	if (sdb == NULL) {
		WARN_ON_ONCE(1);
	} else if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
400
401
402
403
404
		/* error: no data transfered */
		sdb->resid = sdb->length;
	} else {
		sdb->resid = sdb->length - urb->actual_length;
	}
405
	uas_try_complete(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
406
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
407
408
409
}

static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
410
411
412
				      unsigned int pipe, u16 stream_id,
				      struct scsi_cmnd *cmnd,
				      enum dma_data_direction dir)
Matthew Wilcox's avatar
Matthew Wilcox committed
413
414
415
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
416
417
	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
		? scsi_in(cmnd) : scsi_out(cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
418
419
420

	if (!urb)
		goto out;
421
422
	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
			  uas_data_cmplt, cmnd);
423
424
	if (devinfo->use_streams)
		urb->stream_id = stream_id;
Matthew Wilcox's avatar
Matthew Wilcox committed
425
426
427
428
429
430
431
	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
432
				       struct Scsi_Host *shost, u16 stream_id)
Matthew Wilcox's avatar
Matthew Wilcox committed
433
434
435
436
437
438
439
440
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct sense_iu *iu;

	if (!urb)
		goto out;

441
	iu = kzalloc(sizeof(*iu), gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
442
443
444
445
	if (!iu)
		goto free;

	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
446
						uas_stat_cmplt, shost);
Matthew Wilcox's avatar
Matthew Wilcox committed
447
448
449
450
451
452
453
454
455
456
	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,
457
					struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
458
459
460
461
462
463
464
465
466
467
468
469
470
471
{
	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);
472
	iu = kzalloc(sizeof(*iu) + len, gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
473
474
475
476
	if (!iu)
		goto free;

	iu->iu_id = IU_ID_COMMAND;
477
	if (blk_rq_tagged(cmnd->request))
478
		iu->tag = cpu_to_be16(cmnd->request->tag + 2);
479
480
	else
		iu->tag = cpu_to_be16(1);
481
	iu->prio_attr = UAS_SIMPLE_TAG;
Matthew Wilcox's avatar
Matthew Wilcox committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
	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,
							usb_free_urb, NULL);
	urb->transfer_flags |= URB_FREE_BUFFER;
 out:
	return urb;
 free:
	usb_free_urb(urb);
	return NULL;
}

496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
			       u8 function, u16 stream_id)
{
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct task_mgmt_iu *iu;
	int err = -ENOMEM;

	if (!urb)
		goto err;

	iu = kzalloc(sizeof(*iu), gfp);
	if (!iu)
		goto err;

	iu->iu_id = IU_ID_TASK_MGMT;
	iu->tag = cpu_to_be16(stream_id);
	int_to_scsilun(cmnd->device->lun, &iu->lun);

	iu->function = function;
	switch (function) {
	case TMF_ABORT_TASK:
		if (blk_rq_tagged(cmnd->request))
			iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
		else
			iu->task_tag = cpu_to_be16(1);
		break;
	}

	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
			  usb_free_urb, NULL);
	urb->transfer_flags |= URB_FREE_BUFFER;

530
	usb_anchor_urb(urb, &devinfo->cmd_urbs);
531
	err = usb_submit_urb(urb, gfp);
532
533
	if (err) {
		usb_unanchor_urb(urb);
534
		goto err;
535
	}
536
537
538
539
540
541
542
543

	return 0;

err:
	usb_free_urb(urb);
	return err;
}

Matthew Wilcox's avatar
Matthew Wilcox committed
544
545
546
547
548
549
/*
 * 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.
 */

Gerd Hoffmann's avatar
Gerd Hoffmann committed
550
551
static int uas_submit_sense_urb(struct Scsi_Host *shost,
				gfp_t gfp, unsigned int stream)
Matthew Wilcox's avatar
Matthew Wilcox committed
552
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
553
554
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
	struct urb *urb;
Matthew Wilcox's avatar
Matthew Wilcox committed
555

Gerd Hoffmann's avatar
Gerd Hoffmann committed
556
557
558
	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
	if (!urb)
		return SCSI_MLQUEUE_DEVICE_BUSY;
559
	usb_anchor_urb(urb, &devinfo->sense_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
560
	if (usb_submit_urb(urb, gfp)) {
561
		usb_unanchor_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
562
563
564
565
		shost_printk(KERN_INFO, shost,
			     "sense urb submission failure\n");
		usb_free_urb(urb);
		return SCSI_MLQUEUE_DEVICE_BUSY;
Matthew Wilcox's avatar
Matthew Wilcox committed
566
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
567
568
569
570
571
572
573
574
	return 0;
}

static int uas_submit_urbs(struct scsi_cmnd *cmnd,
			   struct uas_dev_info *devinfo, gfp_t gfp)
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
575

576
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
577
	if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
578
579
580
581
		err = uas_submit_sense_urb(cmnd->device->host, gfp,
					   cmdinfo->stream);
		if (err) {
			return err;
Matthew Wilcox's avatar
Matthew Wilcox committed
582
		}
583
		cmdinfo->state &= ~SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
584
585
586
587
	}

	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
588
					devinfo->data_in_pipe, cmdinfo->stream,
589
					cmnd, DMA_FROM_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
590
591
592
593
594
595
		if (!cmdinfo->data_in_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
596
		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
597
		if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) {
598
			usb_unanchor_urb(cmdinfo->data_in_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
599
600
601
602
603
			scmd_printk(KERN_INFO, cmnd,
					"data in urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
604
		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
605
606
607
608
	}

	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
609
					devinfo->data_out_pipe, cmdinfo->stream,
610
					cmnd, DMA_TO_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
611
612
613
614
615
616
		if (!cmdinfo->data_out_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
617
		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
618
		if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) {
619
			usb_unanchor_urb(cmdinfo->data_out_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
620
621
622
623
624
			scmd_printk(KERN_INFO, cmnd,
					"data out urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
625
		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
626
627
628
	}

	if (cmdinfo->state & ALLOC_CMD_URB) {
629
		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
630
631
632
633
634
635
		if (!cmdinfo->cmd_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_CMD_URB;
	}

	if (cmdinfo->state & SUBMIT_CMD_URB) {
636
		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
637
		if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
638
			usb_unanchor_urb(cmdinfo->cmd_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
639
640
641
642
			scmd_printk(KERN_INFO, cmnd,
					"cmd urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
643
		cmdinfo->cmd_urb = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
644
		cmdinfo->state &= ~SUBMIT_CMD_URB;
645
		cmdinfo->state |= COMMAND_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
646
647
648
649
650
	}

	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
651
static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
Matthew Wilcox's avatar
Matthew Wilcox committed
652
653
654
655
656
					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
657
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
658
659
660
661
	int err;

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

662
663
664
665
666
667
	if (devinfo->resetting) {
		cmnd->result = DID_ERROR << 16;
		cmnd->scsi_done(cmnd);
		return 0;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
668
669
670
	spin_lock_irqsave(&devinfo->lock, flags);
	if (devinfo->cmnd) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
671
		return SCSI_MLQUEUE_DEVICE_BUSY;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
672
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
673
674

	if (blk_rq_tagged(cmnd->request)) {
675
		cmdinfo->stream = cmnd->request->tag + 2;
Matthew Wilcox's avatar
Matthew Wilcox committed
676
	} else {
677
		devinfo->cmnd = cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
678
679
680
681
682
		cmdinfo->stream = 1;
	}

	cmnd->scsi_done = done;

Gerd Hoffmann's avatar
Gerd Hoffmann committed
683
	cmdinfo->state = SUBMIT_STATUS_URB |
Matthew Wilcox's avatar
Matthew Wilcox committed
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
			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) {
699
		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
Matthew Wilcox's avatar
Matthew Wilcox committed
700
701
702
703
704
705
		cmdinfo->stream = 0;
	}

	err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
	if (err) {
		/* If we did nothing, give up now */
706
		if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
707
			spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
708
709
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
710
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
711
712
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
713
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
714
715
716
	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
717
718
static DEF_SCSI_QCMD(uas_queuecommand)

719
720
static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
			    const char *fname, u8 function)
Matthew Wilcox's avatar
Matthew Wilcox committed
721
{
722
723
	struct Scsi_Host *shost = cmnd->device->host;
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
Gerd Hoffmann's avatar
Gerd Hoffmann committed
724
	u16 tag = devinfo->qdepth - 1;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
725
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
726

Gerd Hoffmann's avatar
Gerd Hoffmann committed
727
	spin_lock_irqsave(&devinfo->lock, flags);
728
	memset(&devinfo->response, 0, sizeof(devinfo->response));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
729
	if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
730
731
732
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit sense urb failed\n",
			     __func__, fname);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
733
		spin_unlock_irqrestore(&devinfo->lock, flags);
734
735
		return FAILED;
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
736
	if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
737
738
739
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit task mgmt urb failed\n",
			     __func__, fname);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
740
		spin_unlock_irqrestore(&devinfo->lock, flags);
741
742
		return FAILED;
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
743
744
745
	spin_unlock_irqrestore(&devinfo->lock, flags);

	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
		shost_printk(KERN_INFO, shost,
			     "%s: %s timed out\n", __func__, fname);
		return FAILED;
	}
	if (be16_to_cpu(devinfo->response.tag) != tag) {
		shost_printk(KERN_INFO, shost,
			     "%s: %s failed (wrong tag %d/%d)\n", __func__,
			     fname, be16_to_cpu(devinfo->response.tag), tag);
		return FAILED;
	}
	if (devinfo->response.response_code != RC_TMF_COMPLETE) {
		shost_printk(KERN_INFO, shost,
			     "%s: %s failed (rc 0x%x)\n", __func__,
			     fname, devinfo->response.response_code);
		return FAILED;
	}
	return SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
763
764
}

765
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
766
{
767
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
768
769
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	unsigned long flags;
770
	int ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
771

772
	uas_log_cmd_state(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
773
	spin_lock_irqsave(&devinfo->lock, flags);
774
	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
775
	cmdinfo->state |= COMMAND_ABORTED;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
776
	list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
777
	if (cmdinfo->state & IS_IN_WORK_LIST) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
778
		list_del(&cmdinfo->work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
779
780
781
782
783
784
		cmdinfo->state &= ~IS_IN_WORK_LIST;
	}
	if (cmdinfo->state & COMMAND_INFLIGHT) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
	} else {
785
		uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
786
787
788
789
		uas_try_complete(cmnd, __func__);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = SUCCESS;
	}
790
	return ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
791
792
}

793
static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
794
{
795
796
797
	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
Matthew Wilcox committed
798
799
800
801
802
803
804
}

static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
{
	struct scsi_device *sdev = cmnd->device;
	struct uas_dev_info *devinfo = sdev->hostdata;
	struct usb_device *udev = devinfo->udev;
805
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
806

Gerd Hoffmann's avatar
Gerd Hoffmann committed
807
	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
808
	devinfo->resetting = 1;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
809
	uas_abort_work(devinfo);
810
	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
811
812
	usb_kill_anchored_urbs(&devinfo->sense_urbs);
	usb_kill_anchored_urbs(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
813
	uas_zap_dead(devinfo);
814
	uas_free_streams(devinfo);
815
	err = usb_reset_device(udev);
816
817
	if (!err)
		uas_configure_endpoints(devinfo);
818
	devinfo->resetting = 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
819

820
821
822
823
	if (err) {
		shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
		return FAILED;
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
824

825
826
	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
	return SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
827
828
829
830
831
832
833
834
835
836
837
838
}

static int uas_slave_alloc(struct scsi_device *sdev)
{
	sdev->hostdata = (void *)sdev->host->hostdata[0];
	return 0;
}

static int uas_slave_configure(struct scsi_device *sdev)
{
	struct uas_dev_info *devinfo = sdev->hostdata;
	scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
839
	scsi_activate_tcq(sdev, devinfo->qdepth - 3);
Matthew Wilcox's avatar
Matthew Wilcox committed
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
	return 0;
}

static struct scsi_host_template uas_host_template = {
	.module = THIS_MODULE,
	.name = "uas",
	.queuecommand = uas_queuecommand,
	.slave_alloc = uas_slave_alloc,
	.slave_configure = uas_slave_configure,
	.eh_abort_handler = uas_eh_abort_handler,
	.eh_device_reset_handler = uas_eh_device_reset_handler,
	.eh_bus_reset_handler = uas_eh_bus_reset_handler,
	.can_queue = 65536,	/* Is there a limit on the _host_ ? */
	.this_id = -1,
	.sg_tablesize = SG_NONE,
	.cmd_per_lun = 1,	/* until we override it */
	.skip_settle_delay = 1,
	.ordered_tag = 1,
};

static struct usb_device_id uas_usb_ids[] = {
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
	/* 0xaa is a prototype device I happen to have access to */
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, 0xaa) },
	{ }
};
MODULE_DEVICE_TABLE(usb, uas_usb_ids);

869
870
871
872
873
874
875
static int uas_is_interface(struct usb_host_interface *intf)
{
	return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
		intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
		intf->desc.bInterfaceProtocol == USB_PR_UAS);
}

876
877
878
879
880
881
882
883
884
885
886
887
static int uas_isnt_supported(struct usb_device *udev)
{
	struct usb_hcd *hcd = bus_to_hcd(udev->bus);

	dev_warn(&udev->dev, "The driver for the USB controller %s does not "
			"support scatter-gather which is\n",
			hcd->driver->description);
	dev_warn(&udev->dev, "required by the UAS driver. Please try an"
			"alternative USB controller if you wish to use UAS.\n");
	return -ENODEV;
}

888
889
890
891
static int uas_switch_interface(struct usb_device *udev,
						struct usb_interface *intf)
{
	int i;
892
	int sg_supported = udev->bus->sg_tablesize != 0;
893
894
895

	for (i = 0; i < intf->num_altsetting; i++) {
		struct usb_host_interface *alt = &intf->altsetting[i];
896
897
898
899

		if (uas_is_interface(alt)) {
			if (!sg_supported)
				return uas_isnt_supported(udev);
900
901
902
			return usb_set_interface(udev,
						alt->desc.bInterfaceNumber,
						alt->desc.bAlternateSetting);
903
		}
904
905
906
907
908
	}

	return -ENODEV;
}

Matthew Wilcox's avatar
Matthew Wilcox committed
909
910
911
912
913
914
915
916
917
static void uas_configure_endpoints(struct uas_dev_info *devinfo)
{
	struct usb_host_endpoint *eps[4] = { };
	struct usb_interface *intf = devinfo->intf;
	struct usb_device *udev = devinfo->udev;
	struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint;
	unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;

	devinfo->uas_sense_old = 0;
918
	devinfo->cmnd = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950

	for (i = 0; i < n_endpoints; i++) {
		unsigned char *extra = endpoint[i].extra;
		int len = endpoint[i].extralen;
		while (len > 1) {
			if (extra[1] == USB_DT_PIPE_USAGE) {
				unsigned pipe_id = extra[2];
				if (pipe_id > 0 && pipe_id < 5)
					eps[pipe_id - 1] = &endpoint[i];
				break;
			}
			len -= extra[0];
			extra += extra[0];
		}
	}

	/*
	 * Assume that if we didn't find a control pipe descriptor, we're
	 * using a device with old firmware that happens to be set up like
	 * this.
	 */
	if (!eps[0]) {
		devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1);
		devinfo->status_pipe = usb_rcvbulkpipe(udev, 1);
		devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2);
		devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2);

		eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe);
		eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
		eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
	} else {
		devinfo->cmd_pipe = usb_sndbulkpipe(udev,
951
					     usb_endpoint_num(&eps[0]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
952
		devinfo->status_pipe = usb_rcvbulkpipe(udev,
953
					     usb_endpoint_num(&eps[1]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
954
		devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
955
					     usb_endpoint_num(&eps[2]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
956
		devinfo->data_out_pipe = usb_sndbulkpipe(udev,
957
					     usb_endpoint_num(&eps[3]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
958
959
960
961
962
963
964
965
966
967
968
969
	}

	devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256,
								GFP_KERNEL);
	if (devinfo->qdepth < 0) {
		devinfo->qdepth = 256;
		devinfo->use_streams = 0;
	} else {
		devinfo->use_streams = 1;
	}
}

970
971
972
973
974
975
976
977
978
979
980
static void uas_free_streams(struct uas_dev_info *devinfo)
{
	struct usb_device *udev = devinfo->udev;
	struct usb_host_endpoint *eps[3];

	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
	usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
981
982
983
984
985
986
987
988
/*
 * XXX: What I'd like to do here is register a SCSI host for each USB host in
 * the system.  Follow usb-storage's design of registering a SCSI host for
 * each USB device for the moment.  Can implement this by walking up the
 * USB hierarchy until we find a USB host.
 */
static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
989
990
	int result = -ENOMEM;
	struct Scsi_Host *shost = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
991
992
993
	struct uas_dev_info *devinfo;
	struct usb_device *udev = interface_to_usbdev(intf);

994
995
	if (uas_switch_interface(udev, intf))
		return -ENODEV;
Matthew Wilcox's avatar
Matthew Wilcox committed
996
997
998

	devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
	if (!devinfo)
999
		goto set_alt0;
Matthew Wilcox's avatar
Matthew Wilcox committed
1000
1001
1002

	shost = scsi_host_alloc(&uas_host_template, sizeof(void *));
	if (!shost)
1003
		goto set_alt0;
Matthew Wilcox's avatar
Matthew Wilcox committed
1004
1005
1006

	shost->max_cmd_len = 16 + 252;
	shost->max_id = 1;
1007
1008
	shost->max_lun = 256;
	shost->max_channel = 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
1009
1010
1011
1012
	shost->sg_tablesize = udev->bus->sg_tablesize;

	devinfo->intf = intf;
	devinfo->udev = udev;
1013
	devinfo->resetting = 0;
1014
	init_usb_anchor(&devinfo->cmd_urbs);
1015
1016
	init_usb_anchor(&devinfo->sense_urbs);
	init_usb_anchor(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1017
	spin_lock_init(&devinfo->lock);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1018
1019
	INIT_WORK(&devinfo->work, uas_do_work);
	INIT_LIST_HEAD(&devinfo->work_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1020
	INIT_LIST_HEAD(&devinfo->dead_list);
Matthew Wilcox's avatar
Matthew Wilcox committed
1021
1022
	uas_configure_endpoints(devinfo);

Gerd Hoffmann's avatar
Gerd Hoffmann committed
1023
	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
Matthew Wilcox's avatar
Matthew Wilcox committed
1024
	if (result)
1025
		goto free_streams;
1026
1027
1028

	result = scsi_add_host(shost, &intf->dev);
	if (result)
1029
		goto free_streams;
1030

Matthew Wilcox's avatar
Matthew Wilcox committed
1031
1032
1033
1034
1035
	shost->hostdata[0] = (unsigned long)devinfo;

	scsi_scan_host(shost);
	usb_set_intfdata(intf, shost);
	return result;
1036

1037
free_streams:
1038
	uas_free_streams(devinfo);
1039
1040
set_alt0:
	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
Matthew Wilcox's avatar
Matthew Wilcox committed
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
	kfree(devinfo);
	if (shost)
		scsi_host_put(shost);
	return result;
}

static int uas_pre_reset(struct usb_interface *intf)
{
/* XXX: Need to return 1 if it's not our device in error handling */
	return 0;
}

static int uas_post_reset(struct usb_interface *intf)
{
/* XXX: Need to return 1 if it's not our device in error handling */
	return 0;
}

static void uas_disconnect(struct usb_interface *intf)
{
	struct Scsi_Host *shost = usb_get_intfdata(intf);
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];

Gerd Hoffmann's avatar
Gerd Hoffmann committed
1064
	devinfo->resetting = 1;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1065
	cancel_work_sync(&devinfo->work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1066
	uas_abort_work(devinfo);
1067
	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
1068
1069
	usb_kill_anchored_urbs(&devinfo->sense_urbs);
	usb_kill_anchored_urbs(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1070
	uas_zap_dead(devinfo);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1071
	scsi_remove_host(shost);