aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-08-19 19:45:23 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:47 -0400
commitfff9d40ce0eb4b46f3e186823ceab6bc02c3e5d3 (patch)
treed36626195678a7b2b8cd60c5e7bae1af9f04ab62
parenta93ce0244f2e94dd48e0b4a2742a4e3bf196ab53 (diff)
[SCSI] fc class: unblock target after calling terminate callback (take 2)
When we block a rport and the driver implements the terminate callback we will fail IO that was running quickly. However IO that was in the scsi_device/block queue sits there until the dev_loss_tmo fires, and this can make it look like IO is lost because new IO will get executed but that IO stuck in the blocked queue sits there for some time longer. With this patch when the fast io fail tmo fires, we will fail the blocked IO and any new IO. This patch also allows all drivers to partially support the fast io fail tmo. If the terminate io callback is not implemented, we will still fail blocked IO and any new IO, so multipath can handle that. This patch also allows the fc and iscsi classes to implement the same behavior. The timers are just unfornately named differently. This patch also fixes the problem where drivers were unblocking the target in their terminate callback, which was needed for rport removal, but for fast io fail timeout it would cause IO to bounce arround the scsi/block layer and the LLD queuecommand. And it for drivers that could have IO stuck but did not have a terminate callback the unblock calls in the class will fix them. v2. - fix up bit setting style to meet JamesS's pref. - Broke out new host byte error changes to make it easier to read. - added JamesS's ack from list. v1 - initial patch Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Acked-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/scsi_transport_fc.c47
-rw-r--r--include/scsi/scsi_transport_fc.h6
2 files changed, 33 insertions, 20 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index d5f7653bb94b..1e71abf0607a 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2133,8 +2133,7 @@ fc_attach_transport(struct fc_function_template *ft)
2133 SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles); 2133 SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
2134 SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state); 2134 SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
2135 SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id); 2135 SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
2136 if (ft->terminate_rport_io) 2136 SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo);
2137 SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo);
2138 2137
2139 BUG_ON(count > FC_RPORT_NUM_ATTRS); 2138 BUG_ON(count > FC_RPORT_NUM_ATTRS);
2140 2139
@@ -2328,6 +2327,22 @@ fc_remove_host(struct Scsi_Host *shost)
2328} 2327}
2329EXPORT_SYMBOL(fc_remove_host); 2328EXPORT_SYMBOL(fc_remove_host);
2330 2329
2330static void fc_terminate_rport_io(struct fc_rport *rport)
2331{
2332 struct Scsi_Host *shost = rport_to_shost(rport);
2333 struct fc_internal *i = to_fc_internal(shost->transportt);
2334
2335 /* Involve the LLDD if possible to terminate all io on the rport. */
2336 if (i->f->terminate_rport_io)
2337 i->f->terminate_rport_io(rport);
2338
2339 /*
2340 * must unblock to flush queued IO. The caller will have set
2341 * the port_state or flags, so that fc_remote_port_chkready will
2342 * fail IO.
2343 */
2344 scsi_target_unblock(&rport->dev);
2345}
2331 2346
2332/** 2347/**
2333 * fc_starget_delete - called to delete the scsi decendents of an rport 2348 * fc_starget_delete - called to delete the scsi decendents of an rport
@@ -2340,13 +2355,8 @@ fc_starget_delete(struct work_struct *work)
2340{ 2355{
2341 struct fc_rport *rport = 2356 struct fc_rport *rport =
2342 container_of(work, struct fc_rport, stgt_delete_work); 2357 container_of(work, struct fc_rport, stgt_delete_work);
2343 struct Scsi_Host *shost = rport_to_shost(rport);
2344 struct fc_internal *i = to_fc_internal(shost->transportt);
2345
2346 /* Involve the LLDD if possible to terminate all io on the rport. */
2347 if (i->f->terminate_rport_io)
2348 i->f->terminate_rport_io(rport);
2349 2358
2359 fc_terminate_rport_io(rport);
2350 scsi_remove_target(&rport->dev); 2360 scsi_remove_target(&rport->dev);
2351} 2361}
2352 2362
@@ -2372,10 +2382,7 @@ fc_rport_final_delete(struct work_struct *work)
2372 if (rport->flags & FC_RPORT_SCAN_PENDING) 2382 if (rport->flags & FC_RPORT_SCAN_PENDING)
2373 scsi_flush_work(shost); 2383 scsi_flush_work(shost);
2374 2384
2375 /* involve the LLDD to terminate all pending i/o */ 2385 fc_terminate_rport_io(rport);
2376 if (i->f->terminate_rport_io)
2377 i->f->terminate_rport_io(rport);
2378
2379 /* 2386 /*
2380 * Cancel any outstanding timers. These should really exist 2387 * Cancel any outstanding timers. These should really exist
2381 * only when rmmod'ing the LLDD and we're asking for 2388 * only when rmmod'ing the LLDD and we're asking for
@@ -2639,7 +2646,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
2639 2646
2640 spin_lock_irqsave(shost->host_lock, flags); 2647 spin_lock_irqsave(shost->host_lock, flags);
2641 2648
2642 rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; 2649 rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT |
2650 FC_RPORT_DEVLOSS_PENDING);
2643 2651
2644 /* if target, initiate a scan */ 2652 /* if target, initiate a scan */
2645 if (rport->scsi_target_id != -1) { 2653 if (rport->scsi_target_id != -1) {
@@ -2702,6 +2710,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
2702 rport->port_id = ids->port_id; 2710 rport->port_id = ids->port_id;
2703 rport->roles = ids->roles; 2711 rport->roles = ids->roles;
2704 rport->port_state = FC_PORTSTATE_ONLINE; 2712 rport->port_state = FC_PORTSTATE_ONLINE;
2713 rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT;
2705 2714
2706 if (fci->f->dd_fcrport_size) 2715 if (fci->f->dd_fcrport_size)
2707 memset(rport->dd_data, 0, 2716 memset(rport->dd_data, 0,
@@ -2784,7 +2793,6 @@ void
2784fc_remote_port_delete(struct fc_rport *rport) 2793fc_remote_port_delete(struct fc_rport *rport)
2785{ 2794{
2786 struct Scsi_Host *shost = rport_to_shost(rport); 2795 struct Scsi_Host *shost = rport_to_shost(rport);
2787 struct fc_internal *i = to_fc_internal(shost->transportt);
2788 int timeout = rport->dev_loss_tmo; 2796 int timeout = rport->dev_loss_tmo;
2789 unsigned long flags; 2797 unsigned long flags;
2790 2798
@@ -2830,7 +2838,7 @@ fc_remote_port_delete(struct fc_rport *rport)
2830 2838
2831 /* see if we need to kill io faster than waiting for device loss */ 2839 /* see if we need to kill io faster than waiting for device loss */
2832 if ((rport->fast_io_fail_tmo != -1) && 2840 if ((rport->fast_io_fail_tmo != -1) &&
2833 (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io)) 2841 (rport->fast_io_fail_tmo < timeout))
2834 fc_queue_devloss_work(shost, &rport->fail_io_work, 2842 fc_queue_devloss_work(shost, &rport->fail_io_work,
2835 rport->fast_io_fail_tmo * HZ); 2843 rport->fast_io_fail_tmo * HZ);
2836 2844
@@ -2906,7 +2914,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
2906 fc_flush_devloss(shost); 2914 fc_flush_devloss(shost);
2907 2915
2908 spin_lock_irqsave(shost->host_lock, flags); 2916 spin_lock_irqsave(shost->host_lock, flags);
2909 rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; 2917 rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT |
2918 FC_RPORT_DEVLOSS_PENDING);
2910 spin_unlock_irqrestore(shost->host_lock, flags); 2919 spin_unlock_irqrestore(shost->host_lock, flags);
2911 2920
2912 /* ensure any stgt delete functions are done */ 2921 /* ensure any stgt delete functions are done */
@@ -3001,6 +3010,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
3001 rport->supported_classes = FC_COS_UNSPECIFIED; 3010 rport->supported_classes = FC_COS_UNSPECIFIED;
3002 rport->roles = FC_PORT_ROLE_UNKNOWN; 3011 rport->roles = FC_PORT_ROLE_UNKNOWN;
3003 rport->port_state = FC_PORTSTATE_NOTPRESENT; 3012 rport->port_state = FC_PORTSTATE_NOTPRESENT;
3013 rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT;
3004 3014
3005 /* remove the identifiers that aren't used in the consisting binding */ 3015 /* remove the identifiers that aren't used in the consisting binding */
3006 switch (fc_host->tgtid_bind_type) { 3016 switch (fc_host->tgtid_bind_type) {
@@ -3043,13 +3053,12 @@ fc_timeout_fail_rport_io(struct work_struct *work)
3043{ 3053{
3044 struct fc_rport *rport = 3054 struct fc_rport *rport =
3045 container_of(work, struct fc_rport, fail_io_work.work); 3055 container_of(work, struct fc_rport, fail_io_work.work);
3046 struct Scsi_Host *shost = rport_to_shost(rport);
3047 struct fc_internal *i = to_fc_internal(shost->transportt);
3048 3056
3049 if (rport->port_state != FC_PORTSTATE_BLOCKED) 3057 if (rport->port_state != FC_PORTSTATE_BLOCKED)
3050 return; 3058 return;
3051 3059
3052 i->f->terminate_rport_io(rport); 3060 rport->flags |= FC_RPORT_FAST_FAIL_TIMEDOUT;
3061 fc_terminate_rport_io(rport);
3053} 3062}
3054 3063
3055/** 3064/**
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 21018a4df452..fb8d01370663 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -357,6 +357,7 @@ struct fc_rport { /* aka fc_starget_attrs */
357/* bit field values for struct fc_rport "flags" field: */ 357/* bit field values for struct fc_rport "flags" field: */
358#define FC_RPORT_DEVLOSS_PENDING 0x01 358#define FC_RPORT_DEVLOSS_PENDING 0x01
359#define FC_RPORT_SCAN_PENDING 0x02 359#define FC_RPORT_SCAN_PENDING 0x02
360#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x03
360 361
361#define dev_to_rport(d) \ 362#define dev_to_rport(d) \
362 container_of(d, struct fc_rport, dev) 363 container_of(d, struct fc_rport, dev)
@@ -683,7 +684,10 @@ fc_remote_port_chkready(struct fc_rport *rport)
683 result = DID_NO_CONNECT << 16; 684 result = DID_NO_CONNECT << 16;
684 break; 685 break;
685 case FC_PORTSTATE_BLOCKED: 686 case FC_PORTSTATE_BLOCKED:
686 result = DID_IMM_RETRY << 16; 687 if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)
688 result = DID_NO_CONNECT << 16;
689 else
690 result = DID_IMM_RETRY << 16;
687 break; 691 break;
688 default: 692 default:
689 result = DID_NO_CONNECT << 16; 693 result = DID_NO_CONNECT << 16;