diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
| commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
| tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/scsi/scsi_transport_fc.c | |
| parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
| parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) | |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
| -rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 199 |
1 files changed, 143 insertions, 56 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index d7e470a06180..1b214910b714 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
| @@ -53,6 +53,25 @@ static void fc_bsg_remove(struct request_queue *); | |||
| 53 | static void fc_bsg_goose_queue(struct fc_rport *); | 53 | static void fc_bsg_goose_queue(struct fc_rport *); |
| 54 | 54 | ||
| 55 | /* | 55 | /* |
| 56 | * Module Parameters | ||
| 57 | */ | ||
| 58 | |||
| 59 | /* | ||
| 60 | * dev_loss_tmo: the default number of seconds that the FC transport | ||
| 61 | * should insulate the loss of a remote port. | ||
| 62 | * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. | ||
| 63 | */ | ||
| 64 | static unsigned int fc_dev_loss_tmo = 60; /* seconds */ | ||
| 65 | |||
| 66 | module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); | ||
| 67 | MODULE_PARM_DESC(dev_loss_tmo, | ||
| 68 | "Maximum number of seconds that the FC transport should" | ||
| 69 | " insulate the loss of a remote port. Once this value is" | ||
| 70 | " exceeded, the scsi target is removed. Value should be" | ||
| 71 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" | ||
| 72 | " fast_io_fail_tmo is not set."); | ||
| 73 | |||
| 74 | /* | ||
| 56 | * Redefine so that we can have same named attributes in the | 75 | * Redefine so that we can have same named attributes in the |
| 57 | * sdev/starget/host objects. | 76 | * sdev/starget/host objects. |
| 58 | */ | 77 | */ |
| @@ -403,16 +422,16 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, | |||
| 403 | 422 | ||
| 404 | snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), | 423 | snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), |
| 405 | "fc_wq_%d", shost->host_no); | 424 | "fc_wq_%d", shost->host_no); |
| 406 | fc_host->work_q = create_singlethread_workqueue( | 425 | fc_host->work_q = alloc_workqueue(fc_host->work_q_name, 0, 0); |
| 407 | fc_host->work_q_name); | ||
| 408 | if (!fc_host->work_q) | 426 | if (!fc_host->work_q) |
| 409 | return -ENOMEM; | 427 | return -ENOMEM; |
| 410 | 428 | ||
| 429 | fc_host->dev_loss_tmo = fc_dev_loss_tmo; | ||
| 411 | snprintf(fc_host->devloss_work_q_name, | 430 | snprintf(fc_host->devloss_work_q_name, |
| 412 | sizeof(fc_host->devloss_work_q_name), | 431 | sizeof(fc_host->devloss_work_q_name), |
| 413 | "fc_dl_%d", shost->host_no); | 432 | "fc_dl_%d", shost->host_no); |
| 414 | fc_host->devloss_work_q = create_singlethread_workqueue( | 433 | fc_host->devloss_work_q = |
| 415 | fc_host->devloss_work_q_name); | 434 | alloc_workqueue(fc_host->devloss_work_q_name, 0, 0); |
| 416 | if (!fc_host->devloss_work_q) { | 435 | if (!fc_host->devloss_work_q) { |
| 417 | destroy_workqueue(fc_host->work_q); | 436 | destroy_workqueue(fc_host->work_q); |
| 418 | fc_host->work_q = NULL; | 437 | fc_host->work_q = NULL; |
| @@ -462,25 +481,6 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class, | |||
| 462 | NULL); | 481 | NULL); |
| 463 | 482 | ||
| 464 | /* | 483 | /* |
| 465 | * Module Parameters | ||
| 466 | */ | ||
| 467 | |||
| 468 | /* | ||
| 469 | * dev_loss_tmo: the default number of seconds that the FC transport | ||
| 470 | * should insulate the loss of a remote port. | ||
| 471 | * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. | ||
| 472 | */ | ||
| 473 | static unsigned int fc_dev_loss_tmo = 60; /* seconds */ | ||
| 474 | |||
| 475 | module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); | ||
| 476 | MODULE_PARM_DESC(dev_loss_tmo, | ||
| 477 | "Maximum number of seconds that the FC transport should" | ||
| 478 | " insulate the loss of a remote port. Once this value is" | ||
| 479 | " exceeded, the scsi target is removed. Value should be" | ||
| 480 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" | ||
| 481 | " fast_io_fail_tmo is not set."); | ||
| 482 | |||
| 483 | /* | ||
| 484 | * Netlink Infrastructure | 484 | * Netlink Infrastructure |
| 485 | */ | 485 | */ |
| 486 | 486 | ||
| @@ -830,24 +830,32 @@ static FC_DEVICE_ATTR(rport, supported_classes, S_IRUGO, | |||
| 830 | /* | 830 | /* |
| 831 | * dev_loss_tmo attribute | 831 | * dev_loss_tmo attribute |
| 832 | */ | 832 | */ |
| 833 | fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) | 833 | static int fc_str_to_dev_loss(const char *buf, unsigned long *val) |
| 834 | static ssize_t | 834 | { |
| 835 | store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, | 835 | char *cp; |
| 836 | const char *buf, size_t count) | 836 | |
| 837 | *val = simple_strtoul(buf, &cp, 0); | ||
| 838 | if ((*cp && (*cp != '\n')) || (*val < 0)) | ||
| 839 | return -EINVAL; | ||
| 840 | /* | ||
| 841 | * Check for overflow; dev_loss_tmo is u32 | ||
| 842 | */ | ||
| 843 | if (*val > UINT_MAX) | ||
| 844 | return -EINVAL; | ||
| 845 | |||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | static int fc_rport_set_dev_loss_tmo(struct fc_rport *rport, | ||
| 850 | unsigned long val) | ||
| 837 | { | 851 | { |
| 838 | unsigned long val; | ||
| 839 | struct fc_rport *rport = transport_class_to_rport(dev); | ||
| 840 | struct Scsi_Host *shost = rport_to_shost(rport); | 852 | struct Scsi_Host *shost = rport_to_shost(rport); |
| 841 | struct fc_internal *i = to_fc_internal(shost->transportt); | 853 | struct fc_internal *i = to_fc_internal(shost->transportt); |
| 842 | char *cp; | 854 | |
| 843 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || | 855 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || |
| 844 | (rport->port_state == FC_PORTSTATE_DELETED) || | 856 | (rport->port_state == FC_PORTSTATE_DELETED) || |
| 845 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | 857 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) |
| 846 | return -EBUSY; | 858 | return -EBUSY; |
| 847 | val = simple_strtoul(buf, &cp, 0); | ||
| 848 | if ((*cp && (*cp != '\n')) || (val < 0)) | ||
| 849 | return -EINVAL; | ||
| 850 | |||
| 851 | /* | 859 | /* |
| 852 | * Check for overflow; dev_loss_tmo is u32 | 860 | * Check for overflow; dev_loss_tmo is u32 |
| 853 | */ | 861 | */ |
| @@ -863,6 +871,25 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, | |||
| 863 | return -EINVAL; | 871 | return -EINVAL; |
| 864 | 872 | ||
| 865 | i->f->set_rport_dev_loss_tmo(rport, val); | 873 | i->f->set_rport_dev_loss_tmo(rport, val); |
| 874 | return 0; | ||
| 875 | } | ||
| 876 | |||
| 877 | fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) | ||
| 878 | static ssize_t | ||
| 879 | store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, | ||
| 880 | const char *buf, size_t count) | ||
| 881 | { | ||
| 882 | struct fc_rport *rport = transport_class_to_rport(dev); | ||
| 883 | unsigned long val; | ||
| 884 | int rc; | ||
| 885 | |||
| 886 | rc = fc_str_to_dev_loss(buf, &val); | ||
| 887 | if (rc) | ||
| 888 | return rc; | ||
| 889 | |||
| 890 | rc = fc_rport_set_dev_loss_tmo(rport, val); | ||
| 891 | if (rc) | ||
| 892 | return rc; | ||
| 866 | return count; | 893 | return count; |
| 867 | } | 894 | } |
| 868 | static FC_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, | 895 | static FC_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, |
| @@ -1608,8 +1635,35 @@ store_fc_private_host_issue_lip(struct device *dev, | |||
| 1608 | static FC_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, | 1635 | static FC_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, |
| 1609 | store_fc_private_host_issue_lip); | 1636 | store_fc_private_host_issue_lip); |
| 1610 | 1637 | ||
| 1611 | fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); | 1638 | static ssize_t |
| 1639 | store_fc_private_host_dev_loss_tmo(struct device *dev, | ||
| 1640 | struct device_attribute *attr, | ||
| 1641 | const char *buf, size_t count) | ||
| 1642 | { | ||
| 1643 | struct Scsi_Host *shost = transport_class_to_shost(dev); | ||
| 1644 | struct fc_host_attrs *fc_host = shost_to_fc_host(shost); | ||
| 1645 | struct fc_rport *rport; | ||
| 1646 | unsigned long val, flags; | ||
| 1647 | int rc; | ||
| 1648 | |||
| 1649 | rc = fc_str_to_dev_loss(buf, &val); | ||
| 1650 | if (rc) | ||
| 1651 | return rc; | ||
| 1652 | |||
| 1653 | fc_host_dev_loss_tmo(shost) = val; | ||
| 1654 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 1655 | list_for_each_entry(rport, &fc_host->rports, peers) | ||
| 1656 | fc_rport_set_dev_loss_tmo(rport, val); | ||
| 1657 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1658 | return count; | ||
| 1659 | } | ||
| 1612 | 1660 | ||
| 1661 | fc_private_host_show_function(dev_loss_tmo, "%d\n", 20, ); | ||
| 1662 | static FC_DEVICE_ATTR(host, dev_loss_tmo, S_IRUGO | S_IWUSR, | ||
| 1663 | show_fc_host_dev_loss_tmo, | ||
| 1664 | store_fc_private_host_dev_loss_tmo); | ||
| 1665 | |||
| 1666 | fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); | ||
| 1613 | 1667 | ||
| 1614 | /* | 1668 | /* |
| 1615 | * Host Statistics Management | 1669 | * Host Statistics Management |
| @@ -2165,6 +2219,7 @@ fc_attach_transport(struct fc_function_template *ft) | |||
| 2165 | SETUP_HOST_ATTRIBUTE_RW(system_hostname); | 2219 | SETUP_HOST_ATTRIBUTE_RW(system_hostname); |
| 2166 | 2220 | ||
| 2167 | /* Transport-managed attributes */ | 2221 | /* Transport-managed attributes */ |
| 2222 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(dev_loss_tmo); | ||
| 2168 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); | 2223 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); |
| 2169 | if (ft->issue_fc_host_lip) | 2224 | if (ft->issue_fc_host_lip) |
| 2170 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); | 2225 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); |
| @@ -2322,7 +2377,7 @@ fc_flush_devloss(struct Scsi_Host *shost) | |||
| 2322 | * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host. | 2377 | * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host. |
| 2323 | * @shost: Which &Scsi_Host | 2378 | * @shost: Which &Scsi_Host |
| 2324 | * | 2379 | * |
| 2325 | * This routine is expected to be called immediately preceeding the | 2380 | * This routine is expected to be called immediately preceding the |
| 2326 | * a driver's call to scsi_remove_host(). | 2381 | * a driver's call to scsi_remove_host(). |
| 2327 | * | 2382 | * |
| 2328 | * WARNING: A driver utilizing the fc_transport, which fails to call | 2383 | * WARNING: A driver utilizing the fc_transport, which fails to call |
| @@ -2402,7 +2457,7 @@ static void fc_terminate_rport_io(struct fc_rport *rport) | |||
| 2402 | } | 2457 | } |
| 2403 | 2458 | ||
| 2404 | /** | 2459 | /** |
| 2405 | * fc_starget_delete - called to delete the scsi decendents of an rport | 2460 | * fc_starget_delete - called to delete the scsi descendants of an rport |
| 2406 | * @work: remote port to be operated on. | 2461 | * @work: remote port to be operated on. |
| 2407 | * | 2462 | * |
| 2408 | * Deletes target and all sdevs. | 2463 | * Deletes target and all sdevs. |
| @@ -2433,6 +2488,8 @@ fc_rport_final_delete(struct work_struct *work) | |||
| 2433 | unsigned long flags; | 2488 | unsigned long flags; |
| 2434 | int do_callback = 0; | 2489 | int do_callback = 0; |
| 2435 | 2490 | ||
| 2491 | fc_terminate_rport_io(rport); | ||
| 2492 | |||
| 2436 | /* | 2493 | /* |
| 2437 | * if a scan is pending, flush the SCSI Host work_q so that | 2494 | * if a scan is pending, flush the SCSI Host work_q so that |
| 2438 | * that we can reclaim the rport scan work element. | 2495 | * that we can reclaim the rport scan work element. |
| @@ -2440,8 +2497,6 @@ fc_rport_final_delete(struct work_struct *work) | |||
| 2440 | if (rport->flags & FC_RPORT_SCAN_PENDING) | 2497 | if (rport->flags & FC_RPORT_SCAN_PENDING) |
| 2441 | scsi_flush_work(shost); | 2498 | scsi_flush_work(shost); |
| 2442 | 2499 | ||
| 2443 | fc_terminate_rport_io(rport); | ||
| 2444 | |||
| 2445 | /* | 2500 | /* |
| 2446 | * Cancel any outstanding timers. These should really exist | 2501 | * Cancel any outstanding timers. These should really exist |
| 2447 | * only when rmmod'ing the LLDD and we're asking for | 2502 | * only when rmmod'ing the LLDD and we're asking for |
| @@ -2525,7 +2580,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
| 2525 | 2580 | ||
| 2526 | rport->maxframe_size = -1; | 2581 | rport->maxframe_size = -1; |
| 2527 | rport->supported_classes = FC_COS_UNSPECIFIED; | 2582 | rport->supported_classes = FC_COS_UNSPECIFIED; |
| 2528 | rport->dev_loss_tmo = fc_dev_loss_tmo; | 2583 | rport->dev_loss_tmo = fc_host->dev_loss_tmo; |
| 2529 | memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name)); | 2584 | memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name)); |
| 2530 | memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name)); | 2585 | memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name)); |
| 2531 | rport->port_id = ids->port_id; | 2586 | rport->port_id = ids->port_id; |
| @@ -3760,28 +3815,17 @@ fail_host_msg: | |||
| 3760 | static void | 3815 | static void |
| 3761 | fc_bsg_goose_queue(struct fc_rport *rport) | 3816 | fc_bsg_goose_queue(struct fc_rport *rport) |
| 3762 | { | 3817 | { |
| 3763 | int flagset; | ||
| 3764 | unsigned long flags; | ||
| 3765 | |||
| 3766 | if (!rport->rqst_q) | 3818 | if (!rport->rqst_q) |
| 3767 | return; | 3819 | return; |
| 3768 | 3820 | ||
| 3821 | /* | ||
| 3822 | * This get/put dance makes no sense | ||
| 3823 | */ | ||
| 3769 | get_device(&rport->dev); | 3824 | get_device(&rport->dev); |
| 3770 | 3825 | blk_run_queue_async(rport->rqst_q); | |
| 3771 | spin_lock_irqsave(rport->rqst_q->queue_lock, flags); | ||
| 3772 | flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && | ||
| 3773 | !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); | ||
| 3774 | if (flagset) | ||
| 3775 | queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); | ||
| 3776 | __blk_run_queue(rport->rqst_q); | ||
| 3777 | if (flagset) | ||
| 3778 | queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); | ||
| 3779 | spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); | ||
| 3780 | |||
| 3781 | put_device(&rport->dev); | 3826 | put_device(&rport->dev); |
| 3782 | } | 3827 | } |
| 3783 | 3828 | ||
| 3784 | |||
| 3785 | /** | 3829 | /** |
| 3786 | * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD | 3830 | * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD |
| 3787 | * @q: rport request queue | 3831 | * @q: rport request queue |
| @@ -3857,7 +3901,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, | |||
| 3857 | if (!get_device(dev)) | 3901 | if (!get_device(dev)) |
| 3858 | return; | 3902 | return; |
| 3859 | 3903 | ||
| 3860 | while (!blk_queue_plugged(q)) { | 3904 | while (1) { |
| 3861 | if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) && | 3905 | if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) && |
| 3862 | !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) | 3906 | !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) |
| 3863 | break; | 3907 | break; |
| @@ -4044,11 +4088,54 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) | |||
| 4044 | /** | 4088 | /** |
| 4045 | * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports | 4089 | * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports |
| 4046 | * @q: the request_queue that is to be torn down. | 4090 | * @q: the request_queue that is to be torn down. |
| 4091 | * | ||
| 4092 | * Notes: | ||
| 4093 | * Before unregistering the queue empty any requests that are blocked | ||
| 4094 | * | ||
| 4095 | * | ||
| 4047 | */ | 4096 | */ |
| 4048 | static void | 4097 | static void |
| 4049 | fc_bsg_remove(struct request_queue *q) | 4098 | fc_bsg_remove(struct request_queue *q) |
| 4050 | { | 4099 | { |
| 4100 | struct request *req; /* block request */ | ||
| 4101 | int counts; /* totals for request_list count and starved */ | ||
| 4102 | |||
| 4051 | if (q) { | 4103 | if (q) { |
| 4104 | /* Stop taking in new requests */ | ||
| 4105 | spin_lock_irq(q->queue_lock); | ||
| 4106 | blk_stop_queue(q); | ||
| 4107 | |||
| 4108 | /* drain all requests in the queue */ | ||
| 4109 | while (1) { | ||
| 4110 | /* need the lock to fetch a request | ||
| 4111 | * this may fetch the same reqeust as the previous pass | ||
| 4112 | */ | ||
| 4113 | req = blk_fetch_request(q); | ||
| 4114 | /* save requests in use and starved */ | ||
| 4115 | counts = q->rq.count[0] + q->rq.count[1] + | ||
| 4116 | q->rq.starved[0] + q->rq.starved[1]; | ||
| 4117 | spin_unlock_irq(q->queue_lock); | ||
| 4118 | /* any requests still outstanding? */ | ||
| 4119 | if (counts == 0) | ||
| 4120 | break; | ||
| 4121 | |||
| 4122 | /* This may be the same req as the previous iteration, | ||
| 4123 | * always send the blk_end_request_all after a prefetch. | ||
| 4124 | * It is not okay to not end the request because the | ||
| 4125 | * prefetch started the request. | ||
| 4126 | */ | ||
| 4127 | if (req) { | ||
| 4128 | /* return -ENXIO to indicate that this queue is | ||
| 4129 | * going away | ||
| 4130 | */ | ||
| 4131 | req->errors = -ENXIO; | ||
| 4132 | blk_end_request_all(req, -ENXIO); | ||
| 4133 | } | ||
| 4134 | |||
| 4135 | msleep(200); /* allow bsg to possibly finish */ | ||
| 4136 | spin_lock_irq(q->queue_lock); | ||
| 4137 | } | ||
| 4138 | |||
| 4052 | bsg_unregister_queue(q); | 4139 | bsg_unregister_queue(q); |
| 4053 | blk_cleanup_queue(q); | 4140 | blk_cleanup_queue(q); |
| 4054 | } | 4141 | } |
