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 | } |