introduce soft reset handler
Subsystems (2)
PATCH v3 1/1 introduce soft reset handler
Hello Sathya,
thanks for your patch review! Below is the updated version with DiagPending replaced by ioc_reset_in_progress.
On dual port 53C1030 based HBAs such as the LSI22320R, the hard reset handler will cause DID_SOFT_ERROR for innocent devices on the second port. Introduce a mpt_SoftResetHandler() which doesn't cause this issue and slightly improve mpt_HardResetHandler(). Replace DiagPending by ioc_reset_in_progress to check for running resets.
This is mostly a backport of the fusion-4.x driver available from LSI.
Signed-off-by Bernd Schubert <[email protected]>
drivers/message/fusion/mptbase.c | 211 ++++++++++++++++++++++++---- drivers/message/fusion/mptbase.h | 11 + drivers/message/fusion/mptctl.c | 7 drivers/message/fusion/mptsas.c | 4 drivers/message/fusion/mptbase.c | 218 ++++++++++++++++++++++++++++++++------ drivers/message/fusion/mptbase.h | 11 + drivers/message/fusion/mptctl.c | 8 - drivers/message/fusion/mptsas.c | 4 drivers/message/fusion/mptscsih.c | 39 +++--- 5 files changed, 226 insertions(+), 54 deletions(-)
drivers/message/fusion/mptbase.c +189 -29
@@ -5945,7 +5945,7 @@ mpt_timer_expired(unsigned long data)dcprintk (ioc,printk (MYIOC_s_DEBUG_FMT"mpt_timer_expired! \n" , ioc->name));/* Perform a FW reload */ -if (mpt_HardResetHandler (ioc,NO_SLEEP ) <0 ) +if (mpt_SoftHardResetHandler (ioc,NO_SLEEP ) <0 )printk (MYIOC_s_WARN_FMT"Firmware Reload FAILED!\n" , ioc->name);/* No more processing.
@@ -6319,6 +6319,134 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc,/* * Reset Handling */ + +/** +* mpt_SoftResetHandler - Issues a less expensive reset +* @ioc: Pointer to MPT_ADAPTER structure +* @sleepFlag: Indicates if sleep or schedule must be called. + +* +* Returns 0 for SUCCESS or -1 if FAILED. +* +* Message Unit Reset - instructs the IOC to reset the Reply Post and +* Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. +* All posted buffers are freed, and event notification is turned off. +* IOC doesnt reply to any outstanding request. This will transfer IOC +* to READY state. +**/ +static int +mpt_SoftResetHandler (MPT_ADAPTER *ioc,int sleepFlag) +{ +int rc; +int ii; +u8 cb_idx; +unsigned long flags; +u32 ioc_state; +unsigned long time_count; + +dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"SoftResetHandler Entered!\n" , + ioc->name)); + + ioc_state =mpt_GetIocState (ioc,0 ) &MPI_IOC_STATE_MASK ; +if (ioc_state ==MPI_IOC_STATE_FAULT || + ioc_state ==MPI_IOC_STATE_RESET ) { +dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT +"skipping, either in FAULT or RESET state!\n" , ioc->name)); +return -1 ; + } + +spin_lock_irqsave (&ioc->diagLock, flags); +if (ioc->ioc_reset_in_progress) { +spin_unlock_irqrestore (&ioc->diagLock, flags); +return -1 ; + } + ioc->ioc_reset_in_progress =1 ; +spin_unlock_irqrestore (&ioc->diagLock, flags); + + rc =-1 ; + +for (cb_idx =MPT_MAX_PROTOCOL_DRIVERS -1 ; cb_idx; cb_idx--) { +if (MptResetHandlers[cb_idx]) +mpt_signal_reset (cb_idx, ioc,MPT_IOC_SETUP_RESET ); + } + +/* Disable reply interrupts (also blocks FreeQ) */ +CHIPREG_WRITE32 (&ioc->chip->IntMask,0xFFFFFFFF ); + ioc->active =0 ; + time_count = jiffies; + rc =SendIocReset (ioc,MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET , sleepFlag); +if (rc !=0 ) + goto out; + +/* MPT_IOC_PRE_RESET clears pending requests, but MUR +* (MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET) tries to find a DMA request and +* will fault the fw if no request is found. So we need to do +* MPT_IOC_PRE_RESET after MUR */ +for (cb_idx =MPT_MAX_PROTOCOL_DRIVERS -1 ; cb_idx; cb_idx--) { +if (MptResetHandlers[cb_idx]) +mpt_signal_reset (cb_idx, ioc,MPT_IOC_PRE_RESET ); + } + + ioc_state =mpt_GetIocState (ioc,0 ) &MPI_IOC_STATE_MASK ; +if (ioc_state !=MPI_IOC_STATE_READY ) + goto out; + +for (ii =0 ; ii <5 ; ii++) { +/* Get IOC facts! Allow 5 retries */ + rc =GetIocFacts (ioc, sleepFlag,MPT_HOSTEVENT_IOC_RECOVER ); +if (rc ==0 ) +break ; +if (sleepFlag ==CAN_SLEEP ) +msleep (100 ); +else +mdelay (100 ); + } +if (ii ==5 ) + goto out; + + rc =PrimeIocFifos (ioc); +if (rc !=0 ) + goto out; + + rc =SendIocInit (ioc, sleepFlag); +if (rc !=0 ) + goto out; + + rc =SendEventNotification (ioc,1 ); +if (rc !=0 ) + goto out; + +if (ioc->hard_resets <-1 ) + ioc->hard_resets++; + +/* +* At this point, we know soft reset succeeded. +*/ + + ioc->active =1 ; +CHIPREG_WRITE32 (&ioc->chip->IntMask,MPI_HIM_DIM ); + + out: +spin_lock_irqsave (&ioc->diagLock, flags); + ioc->ioc_reset_in_progress =0 ; + ioc->taskmgmt_quiesce_io =0 ; + ioc->taskmgmt_in_progress =0 ; +spin_unlock_irqrestore (&ioc->diagLock, flags); + +if (ioc->active) {/* otherwise, hard reset coming */ +for (cb_idx =MPT_MAX_PROTOCOL_DRIVERS -1 ; cb_idx; cb_idx--) { +if (MptResetHandlers[cb_idx]) +mpt_signal_reset (cb_idx, ioc,MPT_IOC_POST_RESET ); + } + } + +printk (MYIOC_s_INFO_FMT"SoftResetHandler: completed (%d seconds): %s\n" , + ioc->name,jiffies_to_msecs (jiffies - time_count)/1000 , + ((rc ==0 ) ?"SUCCESS" :"FAILED" )); + +return rc; +} +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_HardResetHandler - Generic reset handler
@@ -6340,9 +6468,10 @@ int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {int rc; +u8 cb_idx;unsigned long flags; +unsigned long time_count; -dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"HardResetHandler Entered!\n" , ioc->name));#ifdef MFCNT printk (MYIOC_s_INFO_FMT"HardResetHandler Entered!\n" , ioc->name);printk ("MF count 0x%x !\n" , ioc->mfcnt);
@@ -6352,12 +6481,14 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i* mpt_do_ioc_recovery at any instant in time. */ spin_lock_irqsave (&ioc->diagLock, flags); -if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){ +if (ioc->ioc_reset_in_progress + || (ioc->alt_ioc && ioc->alt_ioc->ioc_reset_in_progress)) {spin_unlock_irqrestore (&ioc->diagLock, flags);return 0 ; - }else { - ioc->diagPending =1 ; } + ioc->ioc_reset_in_progress =1 ; +if (ioc->alt_ioc) + ioc->alt_ioc->ioc_reset_in_progress =1 ;spin_unlock_irqrestore (&ioc->diagLock, flags);/* FIXME: If do_ioc_recovery fails, repeat....
@@ -6368,42 +6499,70 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i* Prevents timeouts occurring during a diagnostic reset...very bad. * For all other protocol drivers, this is a no-op. */ - { -u8 cb_idx; -int r =0 ; - -for (cb_idx =MPT_MAX_PROTOCOL_DRIVERS -1 ; cb_idx; cb_idx--) { -if (MptResetHandlers[cb_idx]) { -dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"Calling IOC reset_setup handler #%d\n" , - ioc->name, cb_idx)); - r +=mpt_signal_reset (cb_idx, ioc,MPT_IOC_SETUP_RESET ); -if (ioc->alt_ioc) { -dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"Calling alt-%s setup reset handler #%d\n" , - ioc->name, ioc->alt_ioc->name, cb_idx)); - r +=mpt_signal_reset (cb_idx, ioc->alt_ioc,MPT_IOC_SETUP_RESET ); - } - } +for (cb_idx =MPT_MAX_PROTOCOL_DRIVERS -1 ; cb_idx; cb_idx--) { +if (MptResetHandlers[cb_idx]) { +mpt_signal_reset (cb_idx, ioc,MPT_IOC_SETUP_RESET ); +if (ioc->alt_ioc) +mpt_signal_reset (cb_idx, ioc->alt_ioc,MPT_IOC_SETUP_RESET ); } } -if ((rc =mpt_do_ioc_recovery (ioc,MPT_HOSTEVENT_IOC_RECOVER , sleepFlag)) !=0 ) { -printk (MYIOC_s_WARN_FMT"Cannot recover rc = %d!\n" , ioc->name, rc); + time_count = jiffies; + rc =mpt_do_ioc_recovery (ioc,MPT_HOSTEVENT_IOC_RECOVER , sleepFlag); +if (rc !=0 ) { + printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", + rc, ioc->name); + }else { +if (ioc->hard_resets <-1 ) + ioc->hard_resets++; } - ioc->reload_fw =0 ; -if (ioc->alt_ioc) - ioc->alt_ioc->reload_fw =0 ;spin_lock_irqsave (&ioc->diagLock, flags); - ioc->diagPending =0 ; -if (ioc->alt_ioc) - ioc->alt_ioc->diagPending =0 ; + ioc->ioc_reset_in_progress =0 ; + ioc->taskmgmt_quiesce_io =0 ; + ioc->taskmgmt_in_progress =0 ; +if (ioc->alt_ioc) { + ioc->alt_ioc->ioc_reset_in_progress =0 ; + ioc->alt_ioc->taskmgmt_quiesce_io =0 ; + ioc->alt_ioc->taskmgmt_in_progress =0 ; + }spin_unlock_irqrestore (&ioc->diagLock, flags); -dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"HardResetHandler rc = %d!\n" , ioc->name, rc)); +for (cb_idx =MPT_MAX_PROTOCOL_DRIVERS -1 ; cb_idx; cb_idx--) { +if (MptResetHandlers[cb_idx]) { +mpt_signal_reset (cb_idx, ioc,MPT_IOC_POST_RESET ); +if (ioc->alt_ioc) +mpt_signal_reset (cb_idx, ioc->alt_ioc,MPT_IOC_POST_RESET ); + } + } +dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"HardResetHandler: completed (%d seconds): %s\n" , + ioc->name,jiffies_to_msecs (jiffies - time_count)/1000 , + ((rc ==0 ) ?"SUCCESS" :"FAILED" )));return rc; } +/** +* mpt_SoftHardResetHandler - Generic reset handler +* @ioc: Pointer to MPT_ADAPTER structure +* @sleepFlag: Indicates if sleep or schedule must be called. +* +* First try to do a soft reset and if this fails, call the +* hard-reset-handler +*/ +int +mpt_SoftHardResetHandler (MPT_ADAPTER *ioc,int sleepFlag) +{ +int rc; + + rc =mpt_SoftResetHandler (ioc, sleepFlag); +if (rc) + rc =mpt_HardResetHandler (ioc, sleepFlag); + +return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void EventDescriptionStr (u8 event,u32 evData0,char *evStr)
@@ -7561,6 +7720,7 @@ EXPORT_SYMBOL(mpt_verify_adapter);EXPORT_SYMBOL (mpt_GetIocState);EXPORT_SYMBOL (mpt_print_ioc_summary);EXPORT_SYMBOL (mpt_HardResetHandler); +EXPORT_SYMBOL (mpt_SoftHardResetHandler);EXPORT_SYMBOL (mpt_config);EXPORT_SYMBOL (mpt_findImVolumes);EXPORT_SYMBOL (mpt_alloc_fw_memory);
drivers/message/fusion/mptbase.h +9 -2
@@ -701,6 +701,9 @@ typedef struct _MPT_ADAPTERMPT_SAS_MGMT sas_mgmt;struct work_struct sas_persist_task; +int taskmgmt_in_progress; +u8 taskmgmt_quiesce_io; +struct work_struct fc_setup_reset_work;struct list_head fc_rports;struct work_struct fc_lsc_work;
@@ -709,6 +712,11 @@ typedef struct _MPT_ADAPTERstruct work_struct fc_rescan_work;char fc_rescan_work_q_name[20 ];struct workqueue_struct *fc_rescan_work_q; + +unsigned long hard_resets;/* driver forced bus resets count */ +unsigned long soft_resets;/* fw/external bus resets count */ +u8 ioc_reset_in_progress; +struct scsi_cmnd **ScsiLookup;spinlock_t scsi_lookup_lock;
@@ -844,8 +852,6 @@ typedef struct _MPT_SCSI_HOST {MPT_FRAME_HDR *cmdPtr;/* Ptr to nonOS request */ struct scsi_cmnd *abortSCpnt;MPT_LOCAL_REPLY localReply;/* internal cmd reply struct */ -unsigned long hard_resets;/* driver forced bus resets count */ -unsigned long soft_resets;/* fw/external bus resets count */ unsigned long timeouts;/* cmd timeouts */ ushort sel_timeout[MPT_MAX_FC_DEVICES ];char *info_kbuf;
@@ -916,6 +922,7 @@ extern int mpt_verify_adapter(int iocidextern u32 mpt_GetIocState (MPT_ADAPTER *ioc,int cooked);extern void mpt_print_ioc_summary (MPT_ADAPTER *ioc,char *buf,int *size,int len,int showlan);extern int mpt_HardResetHandler (MPT_ADAPTER *ioc,int sleepFlag); +extern int mpt_SoftHardResetHandler (MPT_ADAPTER *ioc,int sleepFlag);extern int mpt_config (MPT_ADAPTER *ioc,CONFIGPARMS *cfg);extern int mpt_alloc_fw_memory (MPT_ADAPTER *ioc,int size);extern void mpt_free_fw_memory (MPT_ADAPTER *ioc);
drivers/message/fusion/mptscsih.c +21 -18
@@ -1605,7 +1605,7 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8"TM Handler for type=%x: IOC Not operational (0x%x)!\n" , ioc->name, type, ioc_raw_state);printk (MYIOC_s_WARN_FMT" Issuing HardReset!!\n" , ioc->name); -if (mpt_HardResetHandler (ioc,CAN_SLEEP ) <0 ) +if (mpt_SoftHardResetHandler (ioc,CAN_SLEEP ) <0 )printk (MYIOC_s_WARN_FMT"TMHandler: HardReset " "FAILED!!\n" , ioc->name);return FAILED ;
@@ -1621,8 +1621,8 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8/* Isse the Task Mgmt request. */ -if (hd->hard_resets <-1 ) - hd->hard_resets++; +if (ioc->hard_resets <-1 ) + ioc->hard_resets++; rc =mptscsih_IssueTaskMgmt (hd, type, channel, id, lun, ctx2abort, timeout);
@@ -1724,7 +1724,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd ioc, mf));dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"Calling HardReset! \n" , ioc->name)); - retval =mpt_HardResetHandler (ioc,CAN_SLEEP ); + retval =mpt_SoftHardResetHandler (ioc,CAN_SLEEP );dtmprintk (ioc,printk (MYIOC_s_DEBUG_FMT"rc=%d \n" , ioc->name, retval)); goto fail_out;
@@ -1998,11 +1998,12 @@ int mptscsih_host_reset(struct scsi_cmnd *SCpnt) {MPT_SCSI_HOST * hd; -int retval; +int retval, status;MPT_ADAPTER *ioc;/* If we can't locate the host to reset, then we failed. */ -if ((hd =shost_priv (SCpnt->device->host)) ==NULL ){ + hd =shost_priv (SCpnt->device->host); +if (hd ==NULL ) { printk(KERN_ERR MYNAM ": host reset: " "Can't locate host! (sc=%p)\n", SCpnt);return FAILED ;
@@ -2015,21 +2016,23 @@ mptscsih_host_reset(struct scsi_cmnd *SC/* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ -if (mpt_HardResetHandler (ioc,CAN_SLEEP ) <0 ) { - retval =FAILED ; - }else { + retval =mpt_SoftHardResetHandler (ioc,CAN_SLEEP ); + +if (retval <0 ) + status =FAILED ; +else {/* Make sure TM pending is cleared and TM state is set to * NONE. */ - retval =0 ; + status =SUCCESS ; hd->tmPending =0 ; hd->tmState =TM_STATE_NONE ; }printk (MYIOC_s_INFO_FMT"host reset: %s (sc=%p)\n" , - ioc->name, ((retval ==0 ) ?"SUCCESS" :"FAILED" ), SCpnt); + ioc->name, ((status ==SUCCESS ) ?"SUCCESS" :"FAILED" ), SCpnt); -return retval; +return status; }/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2218,7 +2221,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER **/ if (iocstatus ==MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || hd->cmdPtr) -if (mpt_HardResetHandler (ioc,NO_SLEEP ) <0 ) +if (mpt_SoftHardResetHandler (ioc,NO_SLEEP ) <0 )printk (MYIOC_s_WARN_FMT" Firmware Reload FAILED!!\n" , ioc->name);break ;
@@ -2740,8 +2743,8 @@ mptscsih_event_process(MPT_ADAPTER *ioc,break ;case MPI_EVENT_IOC_BUS_RESET :/* 04 */ case MPI_EVENT_EXT_BUS_RESET :/* 05 */ -if (hd && (ioc->bus_type ==SPI ) && (hd->soft_resets <-1 )) - hd->soft_resets++; +if (hd && (ioc->bus_type ==SPI ) && (ioc->soft_resets <-1 )) + ioc->soft_resets++;break ;case MPI_EVENT_LOGOUT :/* 09 */ /* FIXME! */
@@ -2979,9 +2982,9 @@ mptscsih_timer_expired(unsigned long dat*/ }else {/* Perform a FW reload */ -if (mpt_HardResetHandler (ioc,NO_SLEEP ) <0 ) { -printk (MYIOC_s_WARN_FMT"Firmware Reload FAILED!\n" , ioc->name); - } +if (mpt_SoftHardResetHandler (ioc,NO_SLEEP ) <0 ) +printk (MYIOC_s_WARN_FMT"Firmware Reload FAILED!\n" , + ioc->name); } }else {/* This should NEVER happen */
drivers/message/fusion/mptctl.c +5 -3
@@ -323,7 +323,7 @@ static void mptctl_timeout_expired (MPT_*/ dctlprintk (ioctl->ioc,printk (MYIOC_s_DEBUG_FMT"Calling HardReset! \n" , ioctl->ioc->name)); -mpt_HardResetHandler (ioctl->ioc,CAN_SLEEP ); +mpt_SoftHardResetHandler (ioctl->ioc,CAN_SLEEP ); }return ;
@@ -678,6 +678,8 @@ static int mptctl_do_reset(unsigned longdctlprintk (iocp,printk (MYIOC_s_DEBUG_FMT"mptctl_do_reset called.\n" , iocp->name)); +/* We can't use the soft reset handler here, since only the hard +* reset handler can clear possible fw faults */ if (mpt_HardResetHandler (iocp,CAN_SLEEP ) !=0 ) {printk (MYIOC_s_ERR_FMT"%s@%d::mptctl_do_reset - reset failed.\n" , iocp->name, __FILE__, __LINE__);
@@ -2465,8 +2467,8 @@ mptctl_hp_hostinfo(unsigned long arg, unMPT_SCSI_HOST *hd =shost_priv (ioc->sh);if (hd && (cim_rev ==1 )) { - karg.hard_resets = hd->hard_resets; - karg.soft_resets = hd->soft_resets; + karg.hard_resets = ioc->hard_resets; + karg.soft_resets = ioc->soft_resets; karg.timeouts = hd->timeouts; } }
drivers/message/fusion/mptsas.c +2 -2
@@ -1167,7 +1167,7 @@ static int mptsas_phy_reset(struct sas_pif (!timeleft) {/* On timeout reset the board */ mpt_free_msg_frame (ioc, mf); -mpt_HardResetHandler (ioc,CAN_SLEEP ); +mpt_SoftHardResetHandler (ioc,CAN_SLEEP ); error = -ETIMEDOUT ; goto out_unlock; }
@@ -1345,7 +1345,7 @@ static int mptsas_smp_handler(struct Scsif (!timeleft) {printk (MYIOC_s_ERR_FMT"%s: smp timeout!\n" , ioc->name, __func__);/* On timeout reset the board */ -mpt_HardResetHandler (ioc,CAN_SLEEP ); +mpt_SoftHardResetHandler (ioc,CAN_SLEEP ); ret = -ETIMEDOUT ; goto unmap; }
Signature · 2 lines
Bernd Schubert Q-Leap Networks GmbH