aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-09-25 04:47:08 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-25 18:32:23 -0400
commite064852072c47b69f62325c6b7fa4a58332655bd (patch)
tree6c73f09b979339b6740aafab36835c94e06af591 /drivers/usb
parent0871d7d86ce3788ba40391df3a259df2285776cd (diff)
USB: uas: add locking
Add spinlock to protect uas data structures. [ v2: s/GFP_NOIO/GFP_ATOMIC/, better don't sleep when holding a spinlock ] Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/storage/uas.c51
1 files changed, 44 insertions, 7 deletions
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index df1d72e46933..15789097edd6 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -50,6 +50,7 @@ struct uas_dev_info {
50 unsigned use_streams:1; 50 unsigned use_streams:1;
51 unsigned uas_sense_old:1; 51 unsigned uas_sense_old:1;
52 struct scsi_cmnd *cmnd; 52 struct scsi_cmnd *cmnd;
53 spinlock_t lock;
53}; 54};
54 55
55enum { 56enum {
@@ -91,6 +92,7 @@ static void uas_do_work(struct work_struct *work)
91 struct uas_cmd_info *cmdinfo; 92 struct uas_cmd_info *cmdinfo;
92 struct uas_cmd_info *temp; 93 struct uas_cmd_info *temp;
93 struct list_head list; 94 struct list_head list;
95 unsigned long flags;
94 int err; 96 int err;
95 97
96 spin_lock_irq(&uas_work_lock); 98 spin_lock_irq(&uas_work_lock);
@@ -101,7 +103,10 @@ static void uas_do_work(struct work_struct *work)
101 struct scsi_pointer *scp = (void *)cmdinfo; 103 struct scsi_pointer *scp = (void *)cmdinfo;
102 struct scsi_cmnd *cmnd = container_of(scp, 104 struct scsi_cmnd *cmnd = container_of(scp,
103 struct scsi_cmnd, SCp); 105 struct scsi_cmnd, SCp);
104 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); 106 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
107 spin_lock_irqsave(&devinfo->lock, flags);
108 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
109 spin_unlock_irqrestore(&devinfo->lock, flags);
105 if (err) { 110 if (err) {
106 list_del(&cmdinfo->list); 111 list_del(&cmdinfo->list);
107 spin_lock_irq(&uas_work_lock); 112 spin_lock_irq(&uas_work_lock);
@@ -182,7 +187,9 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
182static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) 187static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
183{ 188{
184 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 189 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
190 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
185 191
192 WARN_ON(!spin_is_locked(&devinfo->lock));
186 if (cmdinfo->state & (COMMAND_INFLIGHT | 193 if (cmdinfo->state & (COMMAND_INFLIGHT |
187 DATA_IN_URB_INFLIGHT | 194 DATA_IN_URB_INFLIGHT |
188 DATA_OUT_URB_INFLIGHT)) 195 DATA_OUT_URB_INFLIGHT))
@@ -222,6 +229,7 @@ static void uas_stat_cmplt(struct urb *urb)
222 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 229 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
223 struct scsi_cmnd *cmnd; 230 struct scsi_cmnd *cmnd;
224 struct uas_cmd_info *cmdinfo; 231 struct uas_cmd_info *cmdinfo;
232 unsigned long flags;
225 u16 tag; 233 u16 tag;
226 234
227 if (urb->status) { 235 if (urb->status) {
@@ -235,6 +243,7 @@ static void uas_stat_cmplt(struct urb *urb)
235 return; 243 return;
236 } 244 }
237 245
246 spin_lock_irqsave(&devinfo->lock, flags);
238 tag = be16_to_cpup(&iu->tag) - 1; 247 tag = be16_to_cpup(&iu->tag) - 1;
239 if (tag == 0) 248 if (tag == 0)
240 cmnd = devinfo->cmnd; 249 cmnd = devinfo->cmnd;
@@ -243,6 +252,7 @@ static void uas_stat_cmplt(struct urb *urb)
243 if (!cmnd) { 252 if (!cmnd) {
244 if (iu->iu_id != IU_ID_RESPONSE) { 253 if (iu->iu_id != IU_ID_RESPONSE) {
245 usb_free_urb(urb); 254 usb_free_urb(urb);
255 spin_unlock_irqrestore(&devinfo->lock, flags);
246 return; 256 return;
247 } 257 }
248 } else { 258 } else {
@@ -262,10 +272,16 @@ static void uas_stat_cmplt(struct urb *urb)
262 uas_sense(urb, cmnd); 272 uas_sense(urb, cmnd);
263 if (cmnd->result != 0) { 273 if (cmnd->result != 0) {
264 /* cancel data transfers on error */ 274 /* cancel data transfers on error */
265 if (cmdinfo->state & DATA_IN_URB_INFLIGHT) 275 if (cmdinfo->state & DATA_IN_URB_INFLIGHT) {
276 spin_unlock_irqrestore(&devinfo->lock, flags);
266 usb_unlink_urb(cmdinfo->data_in_urb); 277 usb_unlink_urb(cmdinfo->data_in_urb);
267 if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) 278 spin_lock_irqsave(&devinfo->lock, flags);
279 }
280 if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) {
281 spin_unlock_irqrestore(&devinfo->lock, flags);
268 usb_unlink_urb(cmdinfo->data_out_urb); 282 usb_unlink_urb(cmdinfo->data_out_urb);
283 spin_lock_irqsave(&devinfo->lock, flags);
284 }
269 } 285 }
270 cmdinfo->state &= ~COMMAND_INFLIGHT; 286 cmdinfo->state &= ~COMMAND_INFLIGHT;
271 uas_try_complete(cmnd, __func__); 287 uas_try_complete(cmnd, __func__);
@@ -285,14 +301,18 @@ static void uas_stat_cmplt(struct urb *urb)
285 "Bogus IU (%d) received on status pipe\n", iu->iu_id); 301 "Bogus IU (%d) received on status pipe\n", iu->iu_id);
286 } 302 }
287 usb_free_urb(urb); 303 usb_free_urb(urb);
304 spin_unlock_irqrestore(&devinfo->lock, flags);
288} 305}
289 306
290static void uas_data_cmplt(struct urb *urb) 307static void uas_data_cmplt(struct urb *urb)
291{ 308{
292 struct scsi_cmnd *cmnd = urb->context; 309 struct scsi_cmnd *cmnd = urb->context;
293 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 310 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
311 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
294 struct scsi_data_buffer *sdb = NULL; 312 struct scsi_data_buffer *sdb = NULL;
313 unsigned long flags;
295 314
315 spin_lock_irqsave(&devinfo->lock, flags);
296 if (cmdinfo->data_in_urb == urb) { 316 if (cmdinfo->data_in_urb == urb) {
297 sdb = scsi_in(cmnd); 317 sdb = scsi_in(cmnd);
298 cmdinfo->state &= ~DATA_IN_URB_INFLIGHT; 318 cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
@@ -308,6 +328,7 @@ static void uas_data_cmplt(struct urb *urb)
308 sdb->resid = sdb->length - urb->actual_length; 328 sdb->resid = sdb->length - urb->actual_length;
309 } 329 }
310 uas_try_complete(cmnd, __func__); 330 uas_try_complete(cmnd, __func__);
331 spin_unlock_irqrestore(&devinfo->lock, flags);
311} 332}
312 333
313static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, 334static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
@@ -474,6 +495,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
474 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 495 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
475 int err; 496 int err;
476 497
498 WARN_ON(!spin_is_locked(&devinfo->lock));
477 if (cmdinfo->state & SUBMIT_STATUS_URB) { 499 if (cmdinfo->state & SUBMIT_STATUS_URB) {
478 err = uas_submit_sense_urb(cmnd->device->host, gfp, 500 err = uas_submit_sense_urb(cmnd->device->host, gfp,
479 cmdinfo->stream); 501 cmdinfo->stream);
@@ -554,12 +576,16 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
554 struct scsi_device *sdev = cmnd->device; 576 struct scsi_device *sdev = cmnd->device;
555 struct uas_dev_info *devinfo = sdev->hostdata; 577 struct uas_dev_info *devinfo = sdev->hostdata;
556 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 578 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
579 unsigned long flags;
557 int err; 580 int err;
558 581
559 BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); 582 BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
560 583
561 if (devinfo->cmnd) 584 spin_lock_irqsave(&devinfo->lock, flags);
585 if (devinfo->cmnd) {
586 spin_unlock_irqrestore(&devinfo->lock, flags);
562 return SCSI_MLQUEUE_DEVICE_BUSY; 587 return SCSI_MLQUEUE_DEVICE_BUSY;
588 }
563 589
564 if (blk_rq_tagged(cmnd->request)) { 590 if (blk_rq_tagged(cmnd->request)) {
565 cmdinfo->stream = cmnd->request->tag + 2; 591 cmdinfo->stream = cmnd->request->tag + 2;
@@ -594,6 +620,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
594 if (err) { 620 if (err) {
595 /* If we did nothing, give up now */ 621 /* If we did nothing, give up now */
596 if (cmdinfo->state & SUBMIT_STATUS_URB) { 622 if (cmdinfo->state & SUBMIT_STATUS_URB) {
623 spin_unlock_irqrestore(&devinfo->lock, flags);
597 return SCSI_MLQUEUE_DEVICE_BUSY; 624 return SCSI_MLQUEUE_DEVICE_BUSY;
598 } 625 }
599 spin_lock(&uas_work_lock); 626 spin_lock(&uas_work_lock);
@@ -602,6 +629,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
602 schedule_work(&uas_work); 629 schedule_work(&uas_work);
603 } 630 }
604 631
632 spin_unlock_irqrestore(&devinfo->lock, flags);
605 return 0; 633 return 0;
606} 634}
607 635
@@ -613,21 +641,25 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
613 struct Scsi_Host *shost = cmnd->device->host; 641 struct Scsi_Host *shost = cmnd->device->host;
614 struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; 642 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
615 u16 tag = devinfo->qdepth - 1; 643 u16 tag = devinfo->qdepth - 1;
644 unsigned long flags;
616 645
646 spin_lock_irqsave(&devinfo->lock, flags);
617 memset(&devinfo->response, 0, sizeof(devinfo->response)); 647 memset(&devinfo->response, 0, sizeof(devinfo->response));
618 if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) { 648 if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
619 shost_printk(KERN_INFO, shost, 649 shost_printk(KERN_INFO, shost,
620 "%s: %s: submit sense urb failed\n", 650 "%s: %s: submit sense urb failed\n",
621 __func__, fname); 651 __func__, fname);
622 return FAILED; 652 return FAILED;
623 } 653 }
624 if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) { 654 if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
625 shost_printk(KERN_INFO, shost, 655 shost_printk(KERN_INFO, shost,
626 "%s: %s: submit task mgmt urb failed\n", 656 "%s: %s: submit task mgmt urb failed\n",
627 __func__, fname); 657 __func__, fname);
628 return FAILED; 658 return FAILED;
629 } 659 }
630 if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) { 660 spin_unlock_irqrestore(&devinfo->lock, flags);
661
662 if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
631 shost_printk(KERN_INFO, shost, 663 shost_printk(KERN_INFO, shost,
632 "%s: %s timed out\n", __func__, fname); 664 "%s: %s timed out\n", __func__, fname);
633 return FAILED; 665 return FAILED;
@@ -650,10 +682,14 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
650static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) 682static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
651{ 683{
652 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; 684 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
685 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
686 unsigned long flags;
653 int ret; 687 int ret;
654 688
655 uas_log_cmd_state(cmnd, __func__); 689 uas_log_cmd_state(cmnd, __func__);
690 spin_lock_irqsave(&devinfo->lock, flags);
656 cmdinfo->state |= COMMAND_ABORTED; 691 cmdinfo->state |= COMMAND_ABORTED;
692 spin_unlock_irqrestore(&devinfo->lock, flags);
657 ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK); 693 ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
658 return ret; 694 return ret;
659} 695}
@@ -875,6 +911,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
875 init_usb_anchor(&devinfo->cmd_urbs); 911 init_usb_anchor(&devinfo->cmd_urbs);
876 init_usb_anchor(&devinfo->sense_urbs); 912 init_usb_anchor(&devinfo->sense_urbs);
877 init_usb_anchor(&devinfo->data_urbs); 913 init_usb_anchor(&devinfo->data_urbs);
914 spin_lock_init(&devinfo->lock);
878 uas_configure_endpoints(devinfo); 915 uas_configure_endpoints(devinfo);
879 916
880 result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3); 917 result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);