diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/scsi/scsi_transport_fc.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 176 |
1 files changed, 125 insertions, 51 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index c6f70dae9b2e..6cfffc88022a 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -27,6 +27,8 @@ | |||
27 | */ | 27 | */ |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/slab.h> | ||
31 | #include <linux/delay.h> | ||
30 | #include <scsi/scsi_device.h> | 32 | #include <scsi/scsi_device.h> |
31 | #include <scsi/scsi_host.h> | 33 | #include <scsi/scsi_host.h> |
32 | #include <scsi/scsi_transport.h> | 34 | #include <scsi/scsi_transport.h> |
@@ -474,7 +476,8 @@ MODULE_PARM_DESC(dev_loss_tmo, | |||
474 | "Maximum number of seconds that the FC transport should" | 476 | "Maximum number of seconds that the FC transport should" |
475 | " insulate the loss of a remote port. Once this value is" | 477 | " insulate the loss of a remote port. Once this value is" |
476 | " exceeded, the scsi target is removed. Value should be" | 478 | " exceeded, the scsi target is removed. Value should be" |
477 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); | 479 | " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" |
480 | " fast_io_fail_tmo is not set."); | ||
478 | 481 | ||
479 | /* | 482 | /* |
480 | * Netlink Infrastructure | 483 | * Netlink Infrastructure |
@@ -648,11 +651,22 @@ static __init int fc_transport_init(void) | |||
648 | return error; | 651 | return error; |
649 | error = transport_class_register(&fc_vport_class); | 652 | error = transport_class_register(&fc_vport_class); |
650 | if (error) | 653 | if (error) |
651 | return error; | 654 | goto unreg_host_class; |
652 | error = transport_class_register(&fc_rport_class); | 655 | error = transport_class_register(&fc_rport_class); |
653 | if (error) | 656 | if (error) |
654 | return error; | 657 | goto unreg_vport_class; |
655 | return transport_class_register(&fc_transport_class); | 658 | error = transport_class_register(&fc_transport_class); |
659 | if (error) | ||
660 | goto unreg_rport_class; | ||
661 | return 0; | ||
662 | |||
663 | unreg_rport_class: | ||
664 | transport_class_unregister(&fc_rport_class); | ||
665 | unreg_vport_class: | ||
666 | transport_class_unregister(&fc_vport_class); | ||
667 | unreg_host_class: | ||
668 | transport_class_unregister(&fc_host_class); | ||
669 | return error; | ||
656 | } | 670 | } |
657 | 671 | ||
658 | static void __exit fc_transport_exit(void) | 672 | static void __exit fc_transport_exit(void) |
@@ -830,9 +844,17 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, | |||
830 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | 844 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) |
831 | return -EBUSY; | 845 | return -EBUSY; |
832 | val = simple_strtoul(buf, &cp, 0); | 846 | val = simple_strtoul(buf, &cp, 0); |
833 | if ((*cp && (*cp != '\n')) || | 847 | if ((*cp && (*cp != '\n')) || (val < 0)) |
834 | (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) | ||
835 | return -EINVAL; | 848 | return -EINVAL; |
849 | |||
850 | /* | ||
851 | * If fast_io_fail is off we have to cap | ||
852 | * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT | ||
853 | */ | ||
854 | if (rport->fast_io_fail_tmo == -1 && | ||
855 | val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) | ||
856 | return -EINVAL; | ||
857 | |||
836 | i->f->set_rport_dev_loss_tmo(rport, val); | 858 | i->f->set_rport_dev_loss_tmo(rport, val); |
837 | return count; | 859 | return count; |
838 | } | 860 | } |
@@ -913,9 +935,16 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, | |||
913 | rport->fast_io_fail_tmo = -1; | 935 | rport->fast_io_fail_tmo = -1; |
914 | else { | 936 | else { |
915 | val = simple_strtoul(buf, &cp, 0); | 937 | val = simple_strtoul(buf, &cp, 0); |
916 | if ((*cp && (*cp != '\n')) || | 938 | if ((*cp && (*cp != '\n')) || (val < 0)) |
917 | (val < 0) || (val >= rport->dev_loss_tmo)) | ||
918 | return -EINVAL; | 939 | return -EINVAL; |
940 | /* | ||
941 | * Cap fast_io_fail by dev_loss_tmo or | ||
942 | * SCSI_DEVICE_BLOCK_MAX_TIMEOUT. | ||
943 | */ | ||
944 | if ((val >= rport->dev_loss_tmo) || | ||
945 | (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) | ||
946 | return -EINVAL; | ||
947 | |||
919 | rport->fast_io_fail_tmo = val; | 948 | rport->fast_io_fail_tmo = val; |
920 | } | 949 | } |
921 | return count; | 950 | return count; |
@@ -1204,6 +1233,15 @@ store_fc_vport_delete(struct device *dev, struct device_attribute *attr, | |||
1204 | { | 1233 | { |
1205 | struct fc_vport *vport = transport_class_to_vport(dev); | 1234 | struct fc_vport *vport = transport_class_to_vport(dev); |
1206 | struct Scsi_Host *shost = vport_to_shost(vport); | 1235 | struct Scsi_Host *shost = vport_to_shost(vport); |
1236 | unsigned long flags; | ||
1237 | |||
1238 | spin_lock_irqsave(shost->host_lock, flags); | ||
1239 | if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { | ||
1240 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1241 | return -EBUSY; | ||
1242 | } | ||
1243 | vport->flags |= FC_VPORT_DELETING; | ||
1244 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1207 | 1245 | ||
1208 | fc_queue_work(shost, &vport->vport_delete_work); | 1246 | fc_queue_work(shost, &vport->vport_delete_work); |
1209 | return count; | 1247 | return count; |
@@ -1793,6 +1831,9 @@ store_fc_host_vport_delete(struct device *dev, struct device_attribute *attr, | |||
1793 | list_for_each_entry(vport, &fc_host->vports, peers) { | 1831 | list_for_each_entry(vport, &fc_host->vports, peers) { |
1794 | if ((vport->channel == 0) && | 1832 | if ((vport->channel == 0) && |
1795 | (vport->port_name == wwpn) && (vport->node_name == wwnn)) { | 1833 | (vport->port_name == wwpn) && (vport->node_name == wwnn)) { |
1834 | if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) | ||
1835 | break; | ||
1836 | vport->flags |= FC_VPORT_DELETING; | ||
1796 | match = 1; | 1837 | match = 1; |
1797 | break; | 1838 | break; |
1798 | } | 1839 | } |
@@ -2384,6 +2425,7 @@ fc_rport_final_delete(struct work_struct *work) | |||
2384 | struct Scsi_Host *shost = rport_to_shost(rport); | 2425 | struct Scsi_Host *shost = rport_to_shost(rport); |
2385 | struct fc_internal *i = to_fc_internal(shost->transportt); | 2426 | struct fc_internal *i = to_fc_internal(shost->transportt); |
2386 | unsigned long flags; | 2427 | unsigned long flags; |
2428 | int do_callback = 0; | ||
2387 | 2429 | ||
2388 | /* | 2430 | /* |
2389 | * if a scan is pending, flush the SCSI Host work_q so that | 2431 | * if a scan is pending, flush the SCSI Host work_q so that |
@@ -2422,8 +2464,15 @@ fc_rport_final_delete(struct work_struct *work) | |||
2422 | * Avoid this call if we already called it when we preserved the | 2464 | * Avoid this call if we already called it when we preserved the |
2423 | * rport for the binding. | 2465 | * rport for the binding. |
2424 | */ | 2466 | */ |
2467 | spin_lock_irqsave(shost->host_lock, flags); | ||
2425 | if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && | 2468 | if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && |
2426 | (i->f->dev_loss_tmo_callbk)) | 2469 | (i->f->dev_loss_tmo_callbk)) { |
2470 | rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; | ||
2471 | do_callback = 1; | ||
2472 | } | ||
2473 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2474 | |||
2475 | if (do_callback) | ||
2427 | i->f->dev_loss_tmo_callbk(rport); | 2476 | i->f->dev_loss_tmo_callbk(rport); |
2428 | 2477 | ||
2429 | fc_bsg_remove(rport->rqst_q); | 2478 | fc_bsg_remove(rport->rqst_q); |
@@ -2970,6 +3019,7 @@ fc_timeout_deleted_rport(struct work_struct *work) | |||
2970 | struct fc_internal *i = to_fc_internal(shost->transportt); | 3019 | struct fc_internal *i = to_fc_internal(shost->transportt); |
2971 | struct fc_host_attrs *fc_host = shost_to_fc_host(shost); | 3020 | struct fc_host_attrs *fc_host = shost_to_fc_host(shost); |
2972 | unsigned long flags; | 3021 | unsigned long flags; |
3022 | int do_callback = 0; | ||
2973 | 3023 | ||
2974 | spin_lock_irqsave(shost->host_lock, flags); | 3024 | spin_lock_irqsave(shost->host_lock, flags); |
2975 | 3025 | ||
@@ -3035,7 +3085,6 @@ fc_timeout_deleted_rport(struct work_struct *work) | |||
3035 | rport->roles = FC_PORT_ROLE_UNKNOWN; | 3085 | rport->roles = FC_PORT_ROLE_UNKNOWN; |
3036 | rport->port_state = FC_PORTSTATE_NOTPRESENT; | 3086 | rport->port_state = FC_PORTSTATE_NOTPRESENT; |
3037 | rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; | 3087 | rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; |
3038 | rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; | ||
3039 | 3088 | ||
3040 | /* | 3089 | /* |
3041 | * Pre-emptively kill I/O rather than waiting for the work queue | 3090 | * Pre-emptively kill I/O rather than waiting for the work queue |
@@ -3045,32 +3094,40 @@ fc_timeout_deleted_rport(struct work_struct *work) | |||
3045 | spin_unlock_irqrestore(shost->host_lock, flags); | 3094 | spin_unlock_irqrestore(shost->host_lock, flags); |
3046 | fc_terminate_rport_io(rport); | 3095 | fc_terminate_rport_io(rport); |
3047 | 3096 | ||
3048 | BUG_ON(rport->port_state != FC_PORTSTATE_NOTPRESENT); | 3097 | spin_lock_irqsave(shost->host_lock, flags); |
3049 | 3098 | ||
3050 | /* remove the identifiers that aren't used in the consisting binding */ | 3099 | if (rport->port_state == FC_PORTSTATE_NOTPRESENT) { /* still missing */ |
3051 | switch (fc_host->tgtid_bind_type) { | 3100 | |
3052 | case FC_TGTID_BIND_BY_WWPN: | 3101 | /* remove the identifiers that aren't used in the consisting binding */ |
3053 | rport->node_name = -1; | 3102 | switch (fc_host->tgtid_bind_type) { |
3054 | rport->port_id = -1; | 3103 | case FC_TGTID_BIND_BY_WWPN: |
3055 | break; | 3104 | rport->node_name = -1; |
3056 | case FC_TGTID_BIND_BY_WWNN: | 3105 | rport->port_id = -1; |
3057 | rport->port_name = -1; | 3106 | break; |
3058 | rport->port_id = -1; | 3107 | case FC_TGTID_BIND_BY_WWNN: |
3059 | break; | 3108 | rport->port_name = -1; |
3060 | case FC_TGTID_BIND_BY_ID: | 3109 | rport->port_id = -1; |
3061 | rport->node_name = -1; | 3110 | break; |
3062 | rport->port_name = -1; | 3111 | case FC_TGTID_BIND_BY_ID: |
3063 | break; | 3112 | rport->node_name = -1; |
3064 | case FC_TGTID_BIND_NONE: /* to keep compiler happy */ | 3113 | rport->port_name = -1; |
3065 | break; | 3114 | break; |
3115 | case FC_TGTID_BIND_NONE: /* to keep compiler happy */ | ||
3116 | break; | ||
3117 | } | ||
3118 | |||
3119 | /* | ||
3120 | * As this only occurs if the remote port (scsi target) | ||
3121 | * went away and didn't come back - we'll remove | ||
3122 | * all attached scsi devices. | ||
3123 | */ | ||
3124 | rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; | ||
3125 | fc_queue_work(shost, &rport->stgt_delete_work); | ||
3126 | |||
3127 | do_callback = 1; | ||
3066 | } | 3128 | } |
3067 | 3129 | ||
3068 | /* | 3130 | spin_unlock_irqrestore(shost->host_lock, flags); |
3069 | * As this only occurs if the remote port (scsi target) | ||
3070 | * went away and didn't come back - we'll remove | ||
3071 | * all attached scsi devices. | ||
3072 | */ | ||
3073 | fc_queue_work(shost, &rport->stgt_delete_work); | ||
3074 | 3131 | ||
3075 | /* | 3132 | /* |
3076 | * Notify the driver that the rport is now dead. The LLDD will | 3133 | * Notify the driver that the rport is now dead. The LLDD will |
@@ -3078,7 +3135,7 @@ fc_timeout_deleted_rport(struct work_struct *work) | |||
3078 | * | 3135 | * |
3079 | * Note: we set the CALLBK_DONE flag above to correspond | 3136 | * Note: we set the CALLBK_DONE flag above to correspond |
3080 | */ | 3137 | */ |
3081 | if (i->f->dev_loss_tmo_callbk) | 3138 | if (do_callback && i->f->dev_loss_tmo_callbk) |
3082 | i->f->dev_loss_tmo_callbk(rport); | 3139 | i->f->dev_loss_tmo_callbk(rport); |
3083 | } | 3140 | } |
3084 | 3141 | ||
@@ -3128,6 +3185,31 @@ fc_scsi_scan_rport(struct work_struct *work) | |||
3128 | spin_unlock_irqrestore(shost->host_lock, flags); | 3185 | spin_unlock_irqrestore(shost->host_lock, flags); |
3129 | } | 3186 | } |
3130 | 3187 | ||
3188 | /** | ||
3189 | * fc_block_scsi_eh - Block SCSI eh thread for blocked fc_rport | ||
3190 | * @cmnd: SCSI command that scsi_eh is trying to recover | ||
3191 | * | ||
3192 | * This routine can be called from a FC LLD scsi_eh callback. It | ||
3193 | * blocks the scsi_eh thread until the fc_rport leaves the | ||
3194 | * FC_PORTSTATE_BLOCKED. This is necessary to avoid the scsi_eh | ||
3195 | * failing recovery actions for blocked rports which would lead to | ||
3196 | * offlined SCSI devices. | ||
3197 | */ | ||
3198 | void fc_block_scsi_eh(struct scsi_cmnd *cmnd) | ||
3199 | { | ||
3200 | struct Scsi_Host *shost = cmnd->device->host; | ||
3201 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); | ||
3202 | unsigned long flags; | ||
3203 | |||
3204 | spin_lock_irqsave(shost->host_lock, flags); | ||
3205 | while (rport->port_state == FC_PORTSTATE_BLOCKED) { | ||
3206 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3207 | msleep(1000); | ||
3208 | spin_lock_irqsave(shost->host_lock, flags); | ||
3209 | } | ||
3210 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3211 | } | ||
3212 | EXPORT_SYMBOL(fc_block_scsi_eh); | ||
3131 | 3213 | ||
3132 | /** | 3214 | /** |
3133 | * fc_vport_setup - allocates and creates a FC virtual port. | 3215 | * fc_vport_setup - allocates and creates a FC virtual port. |
@@ -3301,18 +3383,6 @@ fc_vport_terminate(struct fc_vport *vport) | |||
3301 | unsigned long flags; | 3383 | unsigned long flags; |
3302 | int stat; | 3384 | int stat; |
3303 | 3385 | ||
3304 | spin_lock_irqsave(shost->host_lock, flags); | ||
3305 | if (vport->flags & FC_VPORT_CREATING) { | ||
3306 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3307 | return -EBUSY; | ||
3308 | } | ||
3309 | if (vport->flags & (FC_VPORT_DEL)) { | ||
3310 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3311 | return -EALREADY; | ||
3312 | } | ||
3313 | vport->flags |= FC_VPORT_DELETING; | ||
3314 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
3315 | |||
3316 | if (i->f->vport_delete) | 3386 | if (i->f->vport_delete) |
3317 | stat = i->f->vport_delete(vport); | 3387 | stat = i->f->vport_delete(vport); |
3318 | else | 3388 | else |
@@ -3474,7 +3544,10 @@ fc_bsg_job_timeout(struct request *req) | |||
3474 | if (!done && i->f->bsg_timeout) { | 3544 | if (!done && i->f->bsg_timeout) { |
3475 | /* call LLDD to abort the i/o as it has timed out */ | 3545 | /* call LLDD to abort the i/o as it has timed out */ |
3476 | err = i->f->bsg_timeout(job); | 3546 | err = i->f->bsg_timeout(job); |
3477 | if (err) | 3547 | if (err == -EAGAIN) { |
3548 | job->ref_cnt--; | ||
3549 | return BLK_EH_RESET_TIMER; | ||
3550 | } else if (err) | ||
3478 | printk(KERN_ERR "ERROR: FC BSG request timeout - LLD " | 3551 | printk(KERN_ERR "ERROR: FC BSG request timeout - LLD " |
3479 | "abort failed with status %d\n", err); | 3552 | "abort failed with status %d\n", err); |
3480 | } | 3553 | } |
@@ -3769,8 +3842,9 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, | |||
3769 | return; | 3842 | return; |
3770 | 3843 | ||
3771 | while (!blk_queue_plugged(q)) { | 3844 | while (!blk_queue_plugged(q)) { |
3772 | if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED)) | 3845 | if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) && |
3773 | break; | 3846 | !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) |
3847 | break; | ||
3774 | 3848 | ||
3775 | req = blk_fetch_request(q); | 3849 | req = blk_fetch_request(q); |
3776 | if (!req) | 3850 | if (!req) |
@@ -3779,7 +3853,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, | |||
3779 | if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) { | 3853 | if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) { |
3780 | req->errors = -ENXIO; | 3854 | req->errors = -ENXIO; |
3781 | spin_unlock_irq(q->queue_lock); | 3855 | spin_unlock_irq(q->queue_lock); |
3782 | blk_end_request(req, -ENXIO, blk_rq_bytes(req)); | 3856 | blk_end_request_all(req, -ENXIO); |
3783 | spin_lock_irq(q->queue_lock); | 3857 | spin_lock_irq(q->queue_lock); |
3784 | continue; | 3858 | continue; |
3785 | } | 3859 | } |
@@ -3789,7 +3863,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, | |||
3789 | ret = fc_req_to_bsgjob(shost, rport, req); | 3863 | ret = fc_req_to_bsgjob(shost, rport, req); |
3790 | if (ret) { | 3864 | if (ret) { |
3791 | req->errors = ret; | 3865 | req->errors = ret; |
3792 | blk_end_request(req, ret, blk_rq_bytes(req)); | 3866 | blk_end_request_all(req, ret); |
3793 | spin_lock_irq(q->queue_lock); | 3867 | spin_lock_irq(q->queue_lock); |
3794 | continue; | 3868 | continue; |
3795 | } | 3869 | } |