* fast fail improvements (take2) @ 2008-08-19 23:45 michaelc 2008-08-19 23:45 ` [PATCH 1/9] fc class: unblock target after calling terminate callback (take 2) michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe The following patches were made over scsi-misc. They are a resend of this patchset http://marc.info/?l=linux-scsi&m=121263014808604&w=2 http://marc.info/?l=linux-scsi&m=121263014908607&w=2 http://marc.info/?l=linux-scsi&m=121263014908610&w=2 http://marc.info/?l=linux-scsi&m=121263015008613&w=2 http://marc.info/?l=linux-scsi&m=121263015108620&w=2 http://marc.info/?l=linux-scsi&m=121263015008616&w=2 http://marc.info/?l=linux-scsi&m=121263015208626&w=2 http://marc.info/?l=linux-scsi&m=121263015108623&w=2 and this one http://marc.info/?l=linux-scsi&m=121583046130743&w=2 but I fixed up the bit setting per JamesS's comment, made sure there were no merge conflicts with the current code and fixed up the last patches that broke up the fast fail bits in the block layer. The patches are supposed to handle the following issues we have been hitting with multipath. 1. We only have a choice of REQ_FASTFAIL or normal. Different drivers like multipath only want transport errors (the scsi dh modules can override for specific device errors), but today if a LLD feels it should retry a error on the same path it is overridden due to REQ_FASTFAIL failing all possibley retrybale errors. This causes premature path failures and controller switches which can be expensize. 2. When the fast fail tmo fires IO in the blocked queues are not fast failed. They sit in the queue, so dm-multipath has to wait for the dev_loss_tmo which is normally in minutes where the fast io fail tmo is less than 10 seconds. 3. When drivers block the transport object, they end up returning errors at different times because of the error value they happened to select. And for these errors we can use the same error value and implement the same behavior across drivers so dm-multipath knows what to expect without know what driver is being used. ------------------------------------------------------------ These first two patches fix #2, by making sure fc fails blocked when the fast io fail timer runs. 0001-fc-class-unblock-target-after-calling-terminate-cal.patch 0002-fc-drivers-remove-scsi_target_unblock-calls-in-term.patch They were acked by JamesS on the list, but I rediffed them and fixed up the bit setting. ---------------------------------------------------------- The next patches fix #3. 0003-scsi-add-transport-host-byte-errors-v3.patch 0004-iscsi-class-libiscsi-and-qla4xxx-convert-to-new-tr.patch 0005-fc-class-Add-support-for-new-transport-errors.patch 0006-lpfc-start-to-use-new-trasnport-errors.patch 0007-qla2xxx-use-new-host-byte-transport-errors.patch They build on the first two where we implemented the same fast io fail tmo behavior for iscsi and fc. For these patches I added two new host byte error values. The transport classes and drivers can return these instead of abusing the current ones. They allow the fc and iscsi class to requeue IO until the fast io fail or replacement_timeout timers fire. The fc parts were acked by JamesS. The iscsi parts are ok. The qla2xxx patch is just missing a review by Andrew. ---------------------------------------------------- The last two patches fix #1. 0008-block-separate-failfast-into-multiple-bits.patch 0009-scsi-modify-scsi-to-handle-new-fail-fast-flags.patch They do not have to be merged with the above patches, but I tested them together and combined they fix a lot of issues users have reported. In these patches I just split up FASTFAIL into a driver, device and transport request so the lower levels do not have to faill all errors quickly. ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/9] fc class: unblock target after calling terminate callback (take 2) 2008-08-19 23:45 fast fail improvements (take2) michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 2/9] fc drivers: remove scsi_target_unblock calls in terminate callbacks michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> 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> --- drivers/scsi/scsi_transport_fc.c | 47 ++++++++++++++++++++++--------------- include/scsi/scsi_transport_fc.h | 6 ++++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 56823fd..5168ace 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -2157,8 +2157,7 @@ fc_attach_transport(struct fc_function_template *ft) SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles); SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state); SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id); - if (ft->terminate_rport_io) - SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo); + SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo); BUG_ON(count > FC_RPORT_NUM_ATTRS); @@ -2352,6 +2351,22 @@ fc_remove_host(struct Scsi_Host *shost) } EXPORT_SYMBOL(fc_remove_host); +static void fc_terminate_rport_io(struct fc_rport *rport) +{ + struct Scsi_Host *shost = rport_to_shost(rport); + struct fc_internal *i = to_fc_internal(shost->transportt); + + /* Involve the LLDD if possible to terminate all io on the rport. */ + if (i->f->terminate_rport_io) + i->f->terminate_rport_io(rport); + + /* + * must unblock to flush queued IO. The caller will have set + * the port_state or flags, so that fc_remote_port_chkready will + * fail IO. + */ + scsi_target_unblock(&rport->dev); +} /** * fc_starget_delete - called to delete the scsi decendents of an rport @@ -2364,13 +2379,8 @@ fc_starget_delete(struct work_struct *work) { struct fc_rport *rport = container_of(work, struct fc_rport, stgt_delete_work); - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - - /* Involve the LLDD if possible to terminate all io on the rport. */ - if (i->f->terminate_rport_io) - i->f->terminate_rport_io(rport); + fc_terminate_rport_io(rport); scsi_remove_target(&rport->dev); } @@ -2396,10 +2406,7 @@ fc_rport_final_delete(struct work_struct *work) if (rport->flags & FC_RPORT_SCAN_PENDING) scsi_flush_work(shost); - /* involve the LLDD to terminate all pending i/o */ - if (i->f->terminate_rport_io) - i->f->terminate_rport_io(rport); - + fc_terminate_rport_io(rport); /* * Cancel any outstanding timers. These should really exist * only when rmmod'ing the LLDD and we're asking for @@ -2663,7 +2670,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, spin_lock_irqsave(shost->host_lock, flags); - rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; + rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | + FC_RPORT_DEVLOSS_PENDING); /* if target, initiate a scan */ if (rport->scsi_target_id != -1) { @@ -2726,6 +2734,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, rport->port_id = ids->port_id; rport->roles = ids->roles; rport->port_state = FC_PORTSTATE_ONLINE; + rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; if (fci->f->dd_fcrport_size) memset(rport->dd_data, 0, @@ -2808,7 +2817,6 @@ void fc_remote_port_delete(struct fc_rport *rport) { struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); int timeout = rport->dev_loss_tmo; unsigned long flags; @@ -2854,7 +2862,7 @@ fc_remote_port_delete(struct fc_rport *rport) /* see if we need to kill io faster than waiting for device loss */ if ((rport->fast_io_fail_tmo != -1) && - (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io)) + (rport->fast_io_fail_tmo < timeout)) fc_queue_devloss_work(shost, &rport->fail_io_work, rport->fast_io_fail_tmo * HZ); @@ -2930,7 +2938,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) fc_flush_devloss(shost); spin_lock_irqsave(shost->host_lock, flags); - rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; + rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | + FC_RPORT_DEVLOSS_PENDING); spin_unlock_irqrestore(shost->host_lock, flags); /* ensure any stgt delete functions are done */ @@ -3025,6 +3034,7 @@ fc_timeout_deleted_rport(struct work_struct *work) rport->supported_classes = FC_COS_UNSPECIFIED; rport->roles = FC_PORT_ROLE_UNKNOWN; rport->port_state = FC_PORTSTATE_NOTPRESENT; + rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; /* remove the identifiers that aren't used in the consisting binding */ switch (fc_host->tgtid_bind_type) { @@ -3067,13 +3077,12 @@ fc_timeout_fail_rport_io(struct work_struct *work) { struct fc_rport *rport = container_of(work, struct fc_rport, fail_io_work.work); - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); if (rport->port_state != FC_PORTSTATE_BLOCKED) return; - i->f->terminate_rport_io(rport); + rport->flags |= FC_RPORT_FAST_FAIL_TIMEDOUT; + fc_terminate_rport_io(rport); } /** diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 878373c..347e30f 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -338,6 +338,7 @@ struct fc_rport { /* aka fc_starget_attrs */ /* bit field values for struct fc_rport "flags" field: */ #define FC_RPORT_DEVLOSS_PENDING 0x01 #define FC_RPORT_SCAN_PENDING 0x02 +#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x03 #define dev_to_rport(d) \ container_of(d, struct fc_rport, dev) @@ -664,7 +665,10 @@ fc_remote_port_chkready(struct fc_rport *rport) result = DID_NO_CONNECT << 16; break; case FC_PORTSTATE_BLOCKED: - result = DID_IMM_RETRY << 16; + if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) + result = DID_NO_CONNECT << 16; + else + result = DID_IMM_RETRY << 16; break; default: result = DID_NO_CONNECT << 16; -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/9] fc drivers: remove scsi_target_unblock calls in terminate callbacks 2008-08-19 23:45 ` [PATCH 1/9] fc class: unblock target after calling terminate callback (take 2) michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 3/9] scsi: add transport host byte errors (v3) michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> The fc class now calls scsi_target_unblock after calling the terminate callback, so this patch removes the calls from the drivers. This patch was made over scsi-misc which has the ibmvfc driver. It is also made over the latest qlogic patchset, which added a terminate callback patchset: http://marc.info/?l=linux-scsi&m=121573412422984&w=2 patch with callabck addition http://marc.info/?l=linux-scsi&m=121573444523292&w=2 Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> --- drivers/scsi/ibmvscsi/ibmvfc.c | 2 -- drivers/scsi/lpfc/lpfc_hbadisc.c | 8 -------- drivers/scsi/qla2xxx/qla_attr.c | 1 - 3 files changed, 0 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index ae560bc..a3744fd 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2024,8 +2024,6 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport) spin_unlock_irqrestore(shost->host_lock, flags); } else ibmvfc_issue_fc_host_lip(shost); - - scsi_target_unblock(&rport->dev); LEAVE; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a98d11b..aaf398e 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -88,14 +88,6 @@ lpfc_terminate_rport_io(struct fc_rport *rport) &phba->sli.ring[phba->sli.fcp_ring], ndlp->nlp_sid, 0, LPFC_CTX_TGT); } - - /* - * A device is normally blocked for rediscovery and unblocked when - * devloss timeout happens. In case a vport is removed or driver - * unloaded before devloss timeout happens, we need to unblock here. - */ - scsi_target_unblock(&rport->dev); - return; } /* diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7a4409a..b98ef66 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -993,7 +993,6 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) fc_port_t *fcport = *(fc_port_t **)rport->dd_data; qla2x00_abort_fcport_cmds(fcport); - scsi_target_unblock(&rport->dev); } static int -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/9] scsi: add transport host byte errors (v3) 2008-08-19 23:45 ` [PATCH 2/9] fc drivers: remove scsi_target_unblock calls in terminate callbacks michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 4/9] iscsi class, libiscsi and qla4xxx: convert to new transport host byte values michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> Currently, if there is a transport problem the iscsi drivers will return outstanding commands (commands being exeucted by the driver/fw/hw) with DID_BUS_BUSY and block the session so no new commands can be queued. Commands that are caught between the failure handling and blocking are failed with DID_IMM_RETRY or one of the scsi ml queuecommand return values. When the recovery_timeout fires, the iscsi drivers then fail IO with DID_NO_CONNECT. For fcp, some drivers will fail some outstanding IO (disk but possibly not tape) with DID_BUS_BUSY or DID_ERROR or some other value that causes a retry and hits the scsi_error.c failfast check, block the rport, and commands caught in the race are failed with DID_IMM_RETRY. Other drivers, may hold onto all IO and wait for the terminate_rport_io or dev_loss_tmo_callbk to be called. The following patches attempt to unify what upper layers will see drivers like multipath can make a good guess. This relies on drivers being hooked into their transport class. This first patch just defines two new host byte errors so drivers can return the same value for when a rport/session is blocked and for when the fast_io_fail_tmo fires. The idea is that if the LLD/class detects a problem and is going to block a rport/session, then if the LLD wants or must return the command to scsi-ml, then it can return it with DID_TRANSPORT_DISRUPTED. This will requeue the IO into the same scsi queue it came from, until the fast io fail timer fires and the class decides what to do. When using multipath and the fast_io_fail_tmo fires then the class can fail commands with DID_TRANSPORT_FAILFAST or drivers can use DID_TRANSPORT_FAILFAST in their terminate_rport_io callbacks or the equivlent in iscsi if we ever implement more advanced recovery methods. A LLD, like lpfc, could continue to return DID_ERROR and then it will hit the normal failfast path, so drivers do not have fully be ported to work better. The point of the patches is that upper layers will not see a failure that could be recovered from while the rport/session is blocked until fast_io_fail_tmo/recovery_timeout fires. V3 Remove some comments. V2 Fixed patch/diff errors and renamed DID_TRANSPORT_BLOCKED to DID_TRANSPORT_DISRUPTED. V1 initial patch. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> --- drivers/scsi/constants.c | 3 ++- drivers/scsi/scsi_error.c | 15 ++++++++++++++- include/scsi/scsi.h | 5 +++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 9785d73..4003dee 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1364,7 +1364,8 @@ EXPORT_SYMBOL(scsi_print_sense); static const char * const hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE", +"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST" }; #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) static const char * const driverbyte_table[]={ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 880051c..4e30343 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1351,7 +1351,20 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) case DID_REQUEUE: return ADD_TO_MLQUEUE; - + case DID_TRANSPORT_DISRUPTED: + /* + * LLD/transport was disrupted during processing of the IO. + * The transport class is now blocked/blocking, + * and the transport will decide what to do with the IO + * based on its timers and recovery capablilities. + */ + return ADD_TO_MLQUEUE; + case DID_TRANSPORT_FAILFAST: + /* + * The transport decided to failfast the IO (most likely + * the fast io fail tmo fired), so send IO directly upwards. + */ + return SUCCESS; case DID_ERROR: if (msg_byte(scmd->result) == COMMAND_COMPLETE && status_byte(scmd->result) == RESERVATION_CONFLICT) diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 5c40cc5..8740a16 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -367,6 +367,11 @@ struct scsi_lun { #define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ #define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also * without decrementing the retry count */ +#define DID_TRANSPORT_DISRUPTED 0x0e /* Transport error disrupted execution + * and the driver blocked the port to + * recover the link. Transport class will + * retry or fail IO */ +#define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */ #define DRIVER_OK 0x00 /* Driver status */ /* -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/9] iscsi class, libiscsi and qla4xxx: convert to new transport host byte values 2008-08-19 23:45 ` [PATCH 3/9] scsi: add transport host byte errors (v3) michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 5/9] fc class: Add support for new transport errors michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> This patch converts the iscsi drivers to the new host byte values. v2 Drop some conversions. Want to avoid conflicts with other patches. v1 initial patch. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> --- drivers/scsi/libiscsi.c | 8 +++++--- drivers/scsi/qla4xxx/ql4_isr.c | 4 ++-- drivers/scsi/scsi_transport_iscsi.c | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 299e075..7c35ae6 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1202,7 +1202,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) break; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - sc->result = DID_NO_CONNECT << 16; + sc->result = DID_TRANSPORT_FAILFAST << 16; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; @@ -2334,8 +2334,10 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn, -1, - STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); + if (STOP_CONN_RECOVER) + fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED); + else + fail_all_commands(conn, -1, DID_ERROR); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index a91a57c..799120f 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -139,7 +139,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun)); - cmd->result = DID_BUS_BUSY << 16; + cmd->result = DID_TRANSPORT_DISRUPTED << 16; /* * Mark device missing so that we won't continue to send @@ -243,7 +243,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) qla4xxx_mark_device_missing(ha, ddb_entry); - cmd->result = DID_BUS_BUSY << 16; + cmd->result = DID_TRANSPORT_DISRUPTED << 16; break; case SCS_QUEUE_FULL: diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 043c392..3c612ac 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -374,10 +374,10 @@ int iscsi_session_chkready(struct iscsi_cls_session *session) err = 0; break; case ISCSI_SESSION_FAILED: - err = DID_IMM_RETRY << 16; + err = DID_TRANSPORT_DISRUPTED << 16; break; case ISCSI_SESSION_FREE: - err = DID_NO_CONNECT << 16; + err = DID_TRANSPORT_FAILFAST << 16; break; default: err = DID_NO_CONNECT << 16; -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/9] fc class: Add support for new transport errors 2008-08-19 23:45 ` [PATCH 4/9] iscsi class, libiscsi and qla4xxx: convert to new transport host byte values michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 6/9] lpfc: start to use new trasnport errors michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> If the target is blocked and fast io fail tmo has not fired then we requeue with DID_TRANSPORT_DISRUPTED. Once that tmo fires we fail with DID_TRANSPORT_FAILFAST. v2 - seperate from "fc class: unblock target after calling terminate callback" to make it easier to review. - Add JamesS's ack from list. v2 - initial patch Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Acked-by: James Smart <James.Smart@emulex.com> --- include/scsi/scsi_transport_fc.h | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 347e30f..65d3986 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -660,15 +660,15 @@ fc_remote_port_chkready(struct fc_rport *rport) if (rport->roles & FC_PORT_ROLE_FCP_TARGET) result = 0; else if (rport->flags & FC_RPORT_DEVLOSS_PENDING) - result = DID_IMM_RETRY << 16; + result = DID_TRANSPORT_DISRUPTED << 16; else result = DID_NO_CONNECT << 16; break; case FC_PORTSTATE_BLOCKED: if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) - result = DID_NO_CONNECT << 16; + result = DID_TRANSPORT_FAILFAST << 16; else - result = DID_IMM_RETRY << 16; + result = DID_TRANSPORT_DISRUPTED << 16; break; default: result = DID_NO_CONNECT << 16; -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/9] lpfc: start to use new trasnport errors. 2008-08-19 23:45 ` [PATCH 5/9] fc class: Add support for new transport errors michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 7/9] qla2xxx: use new host byte transport errors michaelc 2008-08-25 1:54 ` [PATCH 6/9] lpfc: start to use new trasnport errors James Smart 0 siblings, 2 replies; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> This patch converts lpfc to use DID_TRANSPORT_DISRUPTED. I did not do the queuecommand conversion of DID_BUS_BUSY because the SCSI_MLQUEUE_TARGET_BUSY patches convert that. Patch was tested with a direct connection by unplugging cables. I did not hit the port of fabric busy paths, but saw that a distro lpfc driver converted that bus busy to DID_TRANSPORT_DISRUPTED. Also it looks like qla2xxx blocks the rport for that case. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> --- drivers/scsi/lpfc/lpfc_scsi.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 1bcebbd..3678adf 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -570,7 +570,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, break; case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: - cmd->result = ScsiResult(DID_BUS_BUSY, 0); + cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); break; case IOSTAT_LOCAL_REJECT: if (lpfc_cmd->result == RJT_UNAVAIL_PERM || @@ -586,7 +586,14 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, if (!pnode || !NLP_CHK_NODE_ACT(pnode) || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) - cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); + /* + * Port is not setup so fail IO with + * DID_TRANSPORT_DISRUPTED, and allow the fc + * class to determine what to do with it when + * its timers fire. + */ + cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, + SAM_STAT_BUSY); } else { cmd->result = ScsiResult(DID_OK, 0); } -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/9] qla2xxx: use new host byte transport errors. 2008-08-19 23:45 ` [PATCH 6/9] lpfc: start to use new trasnport errors michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 8/9] block: separate failfast into multiple bits michaelc 2008-08-25 1:54 ` [PATCH 6/9] lpfc: start to use new trasnport errors James Smart 1 sibling, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie, Andrew Vasquez From: Mike Christie <michaelc@cs.wisc.edu> This has qla2xxx use the new transport error values instead of DID_BUS_BUSY. I am not sure if all the errors in qla_isr.c I changed are transport related. We end up blocking/deleting the rport for all of them so it is better to use the new transport error since the fc classs will decide when to fail the IO. With this patch if I pull a cable then IO that had reached the driver, will be failed with DID_TRANSPORT_DISRUPTED (not including tape). The fc class will then fail the IO when the fast io fail tmo has fired, and the driver will flush any other commands running. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Cc: Andrew Vasquez <andrew.vasquez@qlogic.com> --- drivers/scsi/qla2xxx/qla_isr.c | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 874d802..5fd90ac 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1183,7 +1183,12 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) cp->serial_number, comp_status, atomic_read(&fcport->state))); - cp->result = DID_BUS_BUSY << 16; + /* + * We are going to have the fc class block the rport + * while we try to recover so instruct the mid layer + * to requeue until the class decides how to handle this. + */ + cp->result = DID_TRANSPORT_DISRUPTED << 16; if (atomic_read(&fcport->state) == FCS_ONLINE) { qla2x00_mark_device_lost(ha, fcport, 1, 1); } @@ -1211,7 +1216,12 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) break; case CS_TIMEOUT: - cp->result = DID_BUS_BUSY << 16; + /* + * We are going to have the fc class block the rport + * while we try to recover so instruct the mid layer + * to requeue until the class decides how to handle this. + */ + cp->result = DID_TRANSPORT_DISRUPTED << 16; if (IS_FWI2_CAPABLE(ha)) { DEBUG2(printk(KERN_INFO -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 8/9] block: separate failfast into multiple bits. 2008-08-19 23:45 ` [PATCH 7/9] qla2xxx: use new host byte transport errors michaelc @ 2008-08-19 23:45 ` michaelc 2008-08-19 23:45 ` [PATCH 9/9] scsi: modify scsi to handle new fail fast flags michaelc 0 siblings, 1 reply; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> Multipath is best at handling transport errors. If it gets a device error then there is not much the multipath layer can do. It will just access the same device but from a different path. This patch breaks up failfast into device, transport and driver errors. The multipath layers (md and dm mutlipath) only ask the lower levels to fast fail transport errors. The user of failfast, read ahead, will ask to fast fail on all errors. Note that blk_noretry_request will return true if any failfast bit is set. This allows drivers that do not support the multipath failfast bits to continue to fail on any failfast error like before. Drivers like scsi that are able to fail fast specific errors can check for the specific fail fast type. In the next patch I will convert scsi. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Cc: Jens Axboe <jens.axboe@oracle.com> --- block/blk-core.c | 11 +++++++++-- drivers/md/dm-mpath.c | 2 +- drivers/md/multipath.c | 4 ++-- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_fba.c | 2 +- drivers/scsi/device_handler/scsi_dh_alua.c | 3 ++- drivers/scsi/device_handler/scsi_dh_emc.c | 3 ++- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 6 ++++-- drivers/scsi/device_handler/scsi_dh_rdac.c | 3 ++- drivers/scsi/scsi_transport_spi.c | 4 +++- include/linux/bio.h | 26 +++++++++++++++++--------- include/linux/blkdev.h | 15 ++++++++++++--- 13 files changed, 57 insertions(+), 26 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index fef79cc..bebf311 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1055,8 +1055,15 @@ void init_request_from_bio(struct request *req, struct bio *bio) /* * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) */ - if (bio_rw_ahead(bio) || bio_failfast(bio)) - req->cmd_flags |= REQ_FAILFAST; + if (bio_rw_ahead(bio)) + req->cmd_flags |= (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER); + if (bio_failfast_dev(bio)) + req->cmd_flags |= REQ_FAILFAST_DEV; + if (bio_failfast_transport(bio)) + req->cmd_flags |= REQ_FAILFAST_TRANSPORT; + if (bio_failfast_driver(bio)) + req->cmd_flags |= REQ_FAILFAST_DRIVER; /* * REQ_BARRIER implies no merging, but lets make it explicit diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 71dd65a..b48e201 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -827,7 +827,7 @@ static int multipath_map(struct dm_target *ti, struct bio *bio, dm_bio_record(&mpio->details, bio); map_context->ptr = mpio; - bio->bi_rw |= (1 << BIO_RW_FAILFAST); + bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); r = map_io(m, bio, mpio, 0); if (r < 0 || r == DM_MAPIO_REQUEUE) mempool_free(mpio, m->mpio_pool); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index c4779cc..2426201 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -172,7 +172,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) mp_bh->bio = *bio; mp_bh->bio.bi_sector += multipath->rdev->data_offset; mp_bh->bio.bi_bdev = multipath->rdev->bdev; - mp_bh->bio.bi_rw |= (1 << BIO_RW_FAILFAST); + mp_bh->bio.bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); mp_bh->bio.bi_end_io = multipath_end_request; mp_bh->bio.bi_private = mp_bh; generic_make_request(&mp_bh->bio); @@ -398,7 +398,7 @@ static void multipathd (mddev_t *mddev) *bio = *(mp_bh->master_bio); bio->bi_sector += conf->multipaths[mp_bh->path].rdev->data_offset; bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev; - bio->bi_rw |= (1 << BIO_RW_FAILFAST); + bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); bio->bi_end_io = multipath_end_request; bio->bi_private = mp_bh; generic_make_request(bio); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 85fcb43..7844461 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -544,7 +544,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); - if (req->cmd_flags & REQ_FAILFAST) + if (blk_noretry_request(req)) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = memdev; cqr->memdev = memdev; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 3590fdb..b904099 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1607,7 +1607,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, recid++; } } - if (req->cmd_flags & REQ_FAILFAST) + if (blk_noretry_request(req)) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = startdev; cqr->memdev = startdev; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index aa0c533..115e032 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -355,7 +355,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, recid++; } } - if (req->cmd_flags & REQ_FAILFAST) + if (blk_noretry_request(req)) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = memdev; cqr->memdev = memdev; diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index fcdd73f..0fda1c6 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -109,7 +109,8 @@ static struct request *get_alua_req(struct scsi_device *sdev, } rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER | REQ_NOMERGE; rq->retries = ALUA_FAILOVER_RETRIES; rq->timeout = ALUA_FAILOVER_TIMEOUT; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index aa46b13..f6abeb3 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -304,7 +304,8 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, rq->cmd[4] = len; rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; rq->timeout = CLARIION_TIMEOUT; rq->retries = CLARIION_RETRIES; diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 9c7a1f8..b1e1017 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -112,7 +112,8 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) return SCSI_DH_RES_TEMP_UNAVAIL; req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_FAILFAST; + req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); memset(req->cmd, 0, MAX_COMMAND_SIZE); req->cmd[0] = TEST_UNIT_READY; @@ -205,7 +206,8 @@ static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h) return SCSI_DH_RES_TEMP_UNAVAIL; req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_FAILFAST; + req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(START_STOP); memset(req->cmd, 0, MAX_COMMAND_SIZE); req->cmd[0] = START_STOP; diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index b093a50..ddee8d0 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -228,7 +228,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev, memset(rq->cmd, 0, BLK_MAX_CDB); rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; rq->retries = RDAC_RETRIES; rq->timeout = RDAC_TIMEOUT; diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 75a64a6..b39e12e 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -109,7 +109,9 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd, for(i = 0; i < DV_RETRIES; i++) { result = scsi_execute(sdev, cmd, dir, buffer, bufflen, sense, DV_TIMEOUT, /* retries */ 1, - REQ_FAILFAST); + REQ_FAILFAST_DEV | + REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER); if (result & DRIVER_SENSE) { struct scsi_sense_hdr sshdr_tmp; if (!sshdr) diff --git a/include/linux/bio.h b/include/linux/bio.h index 0933a14..425a4ec 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -147,15 +147,20 @@ struct bio { * bit 0 -- read (not set) or write (set) * bit 1 -- rw-ahead when set * bit 2 -- barrier - * bit 3 -- fail fast, don't want low level driver retries - * bit 4 -- synchronous I/O hint: the block layer will unplug immediately + * bit 3 -- synchronous I/O hint: the block layer will unplug immediately + * bit 4 -- meta data + * bit 5 -- fail fast device errors + * bit 6 -- fail fast transport errors + * bit 7 -- fail fast driver errors */ -#define BIO_RW 0 -#define BIO_RW_AHEAD 1 -#define BIO_RW_BARRIER 2 -#define BIO_RW_FAILFAST 3 -#define BIO_RW_SYNC 4 -#define BIO_RW_META 5 +#define BIO_RW 0 +#define BIO_RW_AHEAD 1 +#define BIO_RW_BARRIER 2 +#define BIO_RW_SYNC 3 +#define BIO_RW_META 4 +#define BIO_RW_FAILFAST_DEV 5 +#define BIO_RW_FAILFAST_TRANSPORT 6 +#define BIO_RW_FAILFAST_DRIVER 7 /* * upper 16 bits of bi_rw define the io priority of this bio @@ -182,7 +187,10 @@ struct bio { #define bio_sectors(bio) ((bio)->bi_size >> 9) #define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_RW_BARRIER)) #define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC)) -#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) +#define bio_failfast_dev(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST_DEV)) +#define bio_failfast_transport(bio) \ + ((bio)->bi_rw & (1 << BIO_RW_FAILFAST_TRANSPORT)) +#define bio_failfast_driver(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST_DRIVER)) #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) #define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) #define bio_empty_barrier(bio) (bio_barrier(bio) && !(bio)->bi_size) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 88d6808..05b41a0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -88,7 +88,9 @@ enum { */ enum rq_flag_bits { __REQ_RW, /* not set, read. set, write */ - __REQ_FAILFAST, /* no low level driver retries */ + __REQ_FAILFAST_DEV, /* no driver retries of device errors */ + __REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */ + __REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */ __REQ_SORTED, /* elevator knows about this request */ __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ __REQ_HARDBARRIER, /* may not be passed by drive either */ @@ -111,7 +113,9 @@ enum rq_flag_bits { }; #define REQ_RW (1 << __REQ_RW) -#define REQ_FAILFAST (1 << __REQ_FAILFAST) +#define REQ_FAILFAST_DEV (1 << __REQ_FAILFAST_DEV) +#define REQ_FAILFAST_TRANSPORT (1 << __REQ_FAILFAST_TRANSPORT) +#define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER) #define REQ_SORTED (1 << __REQ_SORTED) #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) #define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER) @@ -523,7 +527,12 @@ enum { #define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL) #define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE) -#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST) +#define blk_failfast_dev(rq) ((rq)->cmd_flags & REQ_FAILFAST_DEV) +#define blk_failfast_transport(rq) ((rq)->cmd_flags & REQ_FAILFAST_TRANSPORT) +#define blk_failfast_driver(rq) ((rq)->cmd_flags & REQ_FAILFAST_DRIVER) +#define blk_noretry_request(rq) (blk_failfast_dev(rq) || \ + blk_failfast_transport(rq) || \ + blk_failfast_driver(rq)) #define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED) #define blk_account_rq(rq) (blk_rq_started(rq) && blk_fs_request(rq)) -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 9/9] scsi: modify scsi to handle new fail fast flags. 2008-08-19 23:45 ` [PATCH 8/9] block: separate failfast into multiple bits michaelc @ 2008-08-19 23:45 ` michaelc 0 siblings, 0 replies; 11+ messages in thread From: michaelc @ 2008-08-19 23:45 UTC (permalink / raw) To: linux-scsi, jens.axboe; +Cc: Mike Christie From: Mike Christie <michaelc@cs.wisc.edu> This checks the errors the scsi-ml determined were retryable and returns if we should fast fail it based on the request fail fast flags. Without the patch, drivers like lpfc, qla2xxx and fcoe would return DID_ERROR for what it determines is a temporary communication problem. There is no loss of connectivity at that time and the driver thinks that it would be fast to retry at the driver level. SCSI-ml will however sees fast fail on the request and DID_ERROR and will fast fail the io. This will then cause dm-multipath to fail the path and possibley switch target controllers when we should be retrying at the scsi layer. We also were fast failing device errors to dm multiapth when unless the scsi_dh modules think otherwis we want to retry at the scsi layer because multipath can only retry the IO like scsi should have done. multipath is a little dumber though because it does not what the error was for and assumes that it should fail the paths. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Cc: Jens Axboe <jens.axboe@oracle.com> --- drivers/scsi/scsi_error.c | 38 ++++++++++++++++++++++++++++++++++++-- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/scsi_priv.h | 1 + 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4e30343..d02ebc0 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1280,6 +1280,40 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q, } /** + * scsi_noretry_cmd - determinte if command should be failed fast + * @scmd: SCSI cmd to examine. + */ +int scsi_noretry_cmd(struct scsi_cmnd *scmd) +{ + switch (host_byte(scmd->result)) { + case DID_OK: + break; + case DID_BUS_BUSY: + return blk_failfast_transport(scmd->request); + case DID_PARITY: + return blk_failfast_dev(scmd->request); + case DID_ERROR: + if (msg_byte(scmd->result) == COMMAND_COMPLETE && + status_byte(scmd->result) == RESERVATION_CONFLICT) + return 0; + /* fall through */ + case DID_SOFT_ERROR: + return blk_failfast_driver(scmd->request); + } + + switch (status_byte(scmd->result)) { + case CHECK_CONDITION: + /* + * assume caller has checked sense and determinted + * the check condition was retryable. + */ + return blk_failfast_dev(scmd->request); + } + + return 0; +} + +/** * scsi_decide_disposition - Disposition a cmd on return from LLD. * @scmd: SCSI cmd to examine. * @@ -1457,7 +1491,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) * even if the request is marked fast fail, we still requeue * for queue congestion conditions (QUEUE_FULL or BUSY) */ if ((++scmd->retries) <= scmd->allowed - && !blk_noretry_request(scmd->request)) { + && !scsi_noretry_cmd(scmd)) { return NEEDS_RETRY; } else { /* @@ -1582,7 +1616,7 @@ void scsi_eh_flush_done_q(struct list_head *done_q) list_for_each_entry_safe(scmd, next, done_q, eh_entry) { list_del_init(&scmd->eh_entry); if (scsi_device_online(scmd->device) && - !blk_noretry_request(scmd->request) && + !scsi_noretry_cmd(scmd) && (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush" " retry cmd: %p\n", diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ff5d56b..4c95086 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -681,7 +681,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, leftover = req->data_len; /* kill remainder if no retrys */ - if (error && blk_noretry_request(req)) + if (error && scsi_noretry_cmd(cmd)) blk_end_request(req, error, leftover); else { if (requeue) { diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 79f0f75..cfbd8a5 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -62,6 +62,7 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *done_q); int scsi_eh_get_sense(struct list_head *work_q, struct list_head *done_q); +int scsi_noretry_cmd(struct scsi_cmnd *scmd); /* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); -- 1.5.4.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 6/9] lpfc: start to use new trasnport errors. 2008-08-19 23:45 ` [PATCH 6/9] lpfc: start to use new trasnport errors michaelc 2008-08-19 23:45 ` [PATCH 7/9] qla2xxx: use new host byte transport errors michaelc @ 2008-08-25 1:54 ` James Smart 1 sibling, 0 replies; 11+ messages in thread From: James Smart @ 2008-08-25 1:54 UTC (permalink / raw) To: michaelc@cs.wisc.edu; +Cc: linux-scsi@vger.kernel.org, jens.axboe@oracle.com Mike, This patch was superceeded by a change in our 8.2.8 patch set. See: http://marc.info/?l=linux-scsi&m=121962902831367&w=2 thanks -- james s michaelc@cs.wisc.edu wrote: > From: Mike Christie <michaelc@cs.wisc.edu> > > This patch converts lpfc to use DID_TRANSPORT_DISRUPTED. I did not > do the queuecommand conversion of DID_BUS_BUSY because the > SCSI_MLQUEUE_TARGET_BUSY patches convert that. > > Patch was tested with a direct connection by unplugging cables. > I did not hit the port of fabric busy paths, but saw that a distro > lpfc driver converted that bus busy to DID_TRANSPORT_DISRUPTED. > Also it looks like qla2xxx blocks the rport for that case. > > Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> > --- > drivers/scsi/lpfc/lpfc_scsi.c | 11 +++++++++-- > 1 files changed, 9 insertions(+), 2 deletions(-) > > diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c > index 1bcebbd..3678adf 100644 > --- a/drivers/scsi/lpfc/lpfc_scsi.c > +++ b/drivers/scsi/lpfc/lpfc_scsi.c > @@ -570,7 +570,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, > break; > case IOSTAT_NPORT_BSY: > case IOSTAT_FABRIC_BSY: > - cmd->result = ScsiResult(DID_BUS_BUSY, 0); > + cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); > break; > case IOSTAT_LOCAL_REJECT: > if (lpfc_cmd->result == RJT_UNAVAIL_PERM || > @@ -586,7 +586,14 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, > > if (!pnode || !NLP_CHK_NODE_ACT(pnode) > || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) > - cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); > + /* > + * Port is not setup so fail IO with > + * DID_TRANSPORT_DISRUPTED, and allow the fc > + * class to determine what to do with it when > + * its timers fire. > + */ > + cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, > + SAM_STAT_BUSY); > } else { > cmd->result = ScsiResult(DID_OK, 0); > } > -- > 1.5.4.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-08-25 1:54 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-08-19 23:45 fast fail improvements (take2) michaelc 2008-08-19 23:45 ` [PATCH 1/9] fc class: unblock target after calling terminate callback (take 2) michaelc 2008-08-19 23:45 ` [PATCH 2/9] fc drivers: remove scsi_target_unblock calls in terminate callbacks michaelc 2008-08-19 23:45 ` [PATCH 3/9] scsi: add transport host byte errors (v3) michaelc 2008-08-19 23:45 ` [PATCH 4/9] iscsi class, libiscsi and qla4xxx: convert to new transport host byte values michaelc 2008-08-19 23:45 ` [PATCH 5/9] fc class: Add support for new transport errors michaelc 2008-08-19 23:45 ` [PATCH 6/9] lpfc: start to use new trasnport errors michaelc 2008-08-19 23:45 ` [PATCH 7/9] qla2xxx: use new host byte transport errors michaelc 2008-08-19 23:45 ` [PATCH 8/9] block: separate failfast into multiple bits michaelc 2008-08-19 23:45 ` [PATCH 9/9] scsi: modify scsi to handle new fail fast flags michaelc 2008-08-25 1:54 ` [PATCH 6/9] lpfc: start to use new trasnport errors James Smart
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.