aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage/uas.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-06-19 03:54:51 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-25 14:50:59 -0400
commitb1d6769333496b05818fe6cec72ef7f7504ef9e4 (patch)
tree3146a237abac196af8b893f55d8ab7809069a49e /drivers/usb/storage/uas.c
parente9bd7e1a2d34de3b0991c81080d56dc408110833 (diff)
uas: keep track of command state, finish scsi cmd when really done.
Set state bits after submitting data urbs & command urbs, so we know what is in flight. Clear data bits when the data urb is finished, clear command bit when we see the status urb for the command. Finish the scsi command after running both status and data completion handlers for the command. Add a cmd status logging function for debugging purposes. Hook it into the error handler, so we see in the log what status a command is in which the scsi layer wants cancel. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/storage/uas.c')
-rw-r--r--drivers/usb/storage/uas.c86
1 files changed, 71 insertions, 15 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index b01273819692..b589b2e0e928 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -56,6 +56,10 @@ enum {
56 SUBMIT_DATA_OUT_URB = (1 << 5), 56 SUBMIT_DATA_OUT_URB = (1 << 5),
57 ALLOC_CMD_URB = (1 << 6), 57 ALLOC_CMD_URB = (1 << 6),
58 SUBMIT_CMD_URB = (1 << 7), 58 SUBMIT_CMD_URB = (1 << 7),
59 COMMAND_INFLIGHT = (1 << 8),
60 DATA_IN_URB_INFLIGHT = (1 << 9),
61 DATA_OUT_URB_INFLIGHT = (1 << 10),
62 COMMAND_COMPLETED = (1 << 11),
59}; 63};
60 64
61/* Overrides scsi_pointer */ 65/* Overrides scsi_pointer */
@@ -124,7 +128,6 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
124 } 128 }
125 129
126 cmnd->result = sense_iu->status; 130 cmnd->result = sense_iu->status;
127 cmnd->scsi_done(cmnd);
128} 131}
129 132
130static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) 133static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
@@ -148,16 +151,51 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
148 } 151 }
149 152
150 cmnd->result = sense_iu->status; 153 cmnd->result = sense_iu->status;
154}
155
156static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
157{
158 struct uas_cmd_info *ci = (void *)&cmnd->SCp;
159
160 scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
161 "%s%s%s%s%s%s%s%s%s%s%s\n",
162 caller, cmnd, cmnd->request->tag,
163 (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
164 (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
165 (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "",
166 (ci->state & ALLOC_DATA_OUT_URB) ? " a-out" : "",
167 (ci->state & SUBMIT_DATA_OUT_URB) ? " s-out" : "",
168 (ci->state & ALLOC_CMD_URB) ? " a-cmd" : "",
169 (ci->state & SUBMIT_CMD_URB) ? " s-cmd" : "",
170 (ci->state & COMMAND_INFLIGHT) ? " CMD" : "",
171 (ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "",
172 (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "",
173 (ci->state & COMMAND_COMPLETED) ? " done" : "");
174}
175
176static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
177{
178 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
179
180 if (cmdinfo->state & (COMMAND_INFLIGHT |
181 DATA_IN_URB_INFLIGHT |
182 DATA_OUT_URB_INFLIGHT))
183 return -EBUSY;
184 BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
185 cmdinfo->state |= COMMAND_COMPLETED;
186 usb_free_urb(cmdinfo->data_in_urb);
187 usb_free_urb(cmdinfo->data_out_urb);
151 cmnd->scsi_done(cmnd); 188 cmnd->scsi_done(cmnd);
189 return 0;
152} 190}
153 191
154static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, 192static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
155 unsigned direction) 193 unsigned direction)
156{ 194{
157 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 195 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
158 int err; 196 int err;
159 197
160 cmdinfo->state = direction | SUBMIT_STATUS_URB; 198 cmdinfo->state |= direction | SUBMIT_STATUS_URB;
161 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); 199 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
162 if (err) { 200 if (err) {
163 spin_lock(&uas_work_lock); 201 spin_lock(&uas_work_lock);
@@ -173,6 +211,7 @@ static void uas_stat_cmplt(struct urb *urb)
173 struct Scsi_Host *shost = urb->context; 211 struct Scsi_Host *shost = urb->context;
174 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 212 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
175 struct scsi_cmnd *cmnd; 213 struct scsi_cmnd *cmnd;
214 struct uas_cmd_info *cmdinfo;
176 u16 tag; 215 u16 tag;
177 216
178 if (urb->status) { 217 if (urb->status) {
@@ -190,6 +229,7 @@ static void uas_stat_cmplt(struct urb *urb)
190 usb_free_urb(urb); 229 usb_free_urb(urb);
191 return; 230 return;
192 } 231 }
232 cmdinfo = (void *)&cmnd->SCp;
193 233
194 switch (iu->iu_id) { 234 switch (iu->iu_id) {
195 case IU_ID_STATUS: 235 case IU_ID_STATUS:
@@ -202,6 +242,8 @@ static void uas_stat_cmplt(struct urb *urb)
202 uas_sense_old(urb, cmnd); 242 uas_sense_old(urb, cmnd);
203 else 243 else
204 uas_sense(urb, cmnd); 244 uas_sense(urb, cmnd);
245 cmdinfo->state &= ~COMMAND_INFLIGHT;
246 uas_try_complete(cmnd, __func__);
205 break; 247 break;
206 case IU_ID_READ_READY: 248 case IU_ID_READ_READY:
207 uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB); 249 uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
@@ -218,23 +260,36 @@ static void uas_stat_cmplt(struct urb *urb)
218 260
219static void uas_data_cmplt(struct urb *urb) 261static void uas_data_cmplt(struct urb *urb)
220{ 262{
221 struct scsi_data_buffer *sdb = urb->context; 263 struct scsi_cmnd *cmnd = urb->context;
264 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
265 struct scsi_data_buffer *sdb = NULL;
266
267 if (cmdinfo->data_in_urb == urb) {
268 sdb = scsi_in(cmnd);
269 cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
270 } else if (cmdinfo->data_out_urb == urb) {
271 sdb = scsi_out(cmnd);
272 cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
273 }
274 BUG_ON(sdb == NULL);
222 sdb->resid = sdb->length - urb->actual_length; 275 sdb->resid = sdb->length - urb->actual_length;
223 usb_free_urb(urb); 276 uas_try_complete(cmnd, __func__);
224} 277}
225 278
226static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, 279static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
227 unsigned int pipe, u16 stream_id, 280 unsigned int pipe, u16 stream_id,
228 struct scsi_data_buffer *sdb, 281 struct scsi_cmnd *cmnd,
229 enum dma_data_direction dir) 282 enum dma_data_direction dir)
230{ 283{
231 struct usb_device *udev = devinfo->udev; 284 struct usb_device *udev = devinfo->udev;
232 struct urb *urb = usb_alloc_urb(0, gfp); 285 struct urb *urb = usb_alloc_urb(0, gfp);
286 struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
287 ? scsi_in(cmnd) : scsi_out(cmnd);
233 288
234 if (!urb) 289 if (!urb)
235 goto out; 290 goto out;
236 usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, 291 usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
237 sdb); 292 uas_data_cmplt, cmnd);
238 if (devinfo->use_streams) 293 if (devinfo->use_streams)
239 urb->stream_id = stream_id; 294 urb->stream_id = stream_id;
240 urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; 295 urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
@@ -350,7 +405,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
350 if (cmdinfo->state & ALLOC_DATA_IN_URB) { 405 if (cmdinfo->state & ALLOC_DATA_IN_URB) {
351 cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, 406 cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
352 devinfo->data_in_pipe, cmdinfo->stream, 407 devinfo->data_in_pipe, cmdinfo->stream,
353 scsi_in(cmnd), DMA_FROM_DEVICE); 408 cmnd, DMA_FROM_DEVICE);
354 if (!cmdinfo->data_in_urb) 409 if (!cmdinfo->data_in_urb)
355 return SCSI_MLQUEUE_DEVICE_BUSY; 410 return SCSI_MLQUEUE_DEVICE_BUSY;
356 cmdinfo->state &= ~ALLOC_DATA_IN_URB; 411 cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@@ -363,12 +418,13 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
363 return SCSI_MLQUEUE_DEVICE_BUSY; 418 return SCSI_MLQUEUE_DEVICE_BUSY;
364 } 419 }
365 cmdinfo->state &= ~SUBMIT_DATA_IN_URB; 420 cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
421 cmdinfo->state |= DATA_IN_URB_INFLIGHT;
366 } 422 }
367 423
368 if (cmdinfo->state & ALLOC_DATA_OUT_URB) { 424 if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
369 cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, 425 cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
370 devinfo->data_out_pipe, cmdinfo->stream, 426 devinfo->data_out_pipe, cmdinfo->stream,
371 scsi_out(cmnd), DMA_TO_DEVICE); 427 cmnd, DMA_TO_DEVICE);
372 if (!cmdinfo->data_out_urb) 428 if (!cmdinfo->data_out_urb)
373 return SCSI_MLQUEUE_DEVICE_BUSY; 429 return SCSI_MLQUEUE_DEVICE_BUSY;
374 cmdinfo->state &= ~ALLOC_DATA_OUT_URB; 430 cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
@@ -381,6 +437,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
381 return SCSI_MLQUEUE_DEVICE_BUSY; 437 return SCSI_MLQUEUE_DEVICE_BUSY;
382 } 438 }
383 cmdinfo->state &= ~SUBMIT_DATA_OUT_URB; 439 cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
440 cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
384 } 441 }
385 442
386 if (cmdinfo->state & ALLOC_CMD_URB) { 443 if (cmdinfo->state & ALLOC_CMD_URB) {
@@ -398,6 +455,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
398 return SCSI_MLQUEUE_DEVICE_BUSY; 455 return SCSI_MLQUEUE_DEVICE_BUSY;
399 } 456 }
400 cmdinfo->state &= ~SUBMIT_CMD_URB; 457 cmdinfo->state &= ~SUBMIT_CMD_URB;
458 cmdinfo->state |= COMMAND_INFLIGHT;
401 } 459 }
402 460
403 return 0; 461 return 0;
@@ -464,9 +522,7 @@ static DEF_SCSI_QCMD(uas_queuecommand)
464 522
465static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) 523static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
466{ 524{
467 struct scsi_device *sdev = cmnd->device; 525 uas_log_cmd_state(cmnd, __func__);
468 sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__,
469 cmnd->request->tag);
470 526
471/* XXX: Send ABORT TASK Task Management command */ 527/* XXX: Send ABORT TASK Task Management command */
472 return FAILED; 528 return FAILED;