1) cleanup ioc_reset callback handlers, introducing wrappers for synronizing error recovery (mpt_set_taskmgmt_in_progress_flag, mpt_clear_taskmgmt_in_progress_flag), as the fusion firmware only handles one task management request at a time. 2) rewrite of all internal generated functions that issue commands to firmware, porting them to be single threaded using the generic MPT_MGMT struct. Signed-off-by: Eric Moore <Eric.Moore@xxxxxxx> --- b/drivers/message/fusion/mptsas.c 2007-09-17 16:35:06.000000000 -0600 +++ a/drivers/message/fusion/mptsas.c 2007-09-17 19:35:03.000000000 -0600 @@ -600,12 +600,12 @@ mptsas_target_reset_queue(MPT_ADAPTER *i sizeof(*sas_event_data)); list_add_tail(&target_reset_list->list, &hd->target_reset_list); - if (hd->resetPending) + if (ioc->ioc_reset_in_progress) return; if (mptsas_target_reset(ioc, channel, id)) { target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; + ioc->ioc_reset_in_progress = 1; } } @@ -638,7 +638,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *i sas_event_data = &target_reset_list->sas_event_data; id = sas_event_data->TargetID; channel = sas_event_data->Bus; - hd->resetPending = 0; + ioc->ioc_reset_in_progress = 0; /* * retry target reset @@ -646,7 +646,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *i if (!target_reset_list->target_reset_issued) { if (mptsas_target_reset(ioc, channel, id)) { target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; + ioc->ioc_reset_in_progress = 1; } return; } @@ -696,7 +696,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *i if (mptsas_target_reset(ioc, channel, id)) { target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; + ioc->ioc_reset_in_progress = 1; } } @@ -716,41 +716,56 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *io } /** - * mptscsih_ioc_reset - * - * @ioc - * @reset_phase + * mptsas_ioc_reset - + * @ioc: Pointer to MPT_ADAPTER structure + * @reset_phase: * **/ static int mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_SCSI_HOST *hd; + MPT_SCSI_HOST *hd; struct mptsas_target_reset_event *target_reset_list, *n; int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); + if ((ioc->bus_type != SAS) || (!rc)) + return rc; - if (ioc->bus_type != SAS) - goto out; - - if (reset_phase != MPT_IOC_POST_RESET) - goto out; - - if (!ioc->sh || !ioc->sh->hostdata) - goto out; - hd = shost_priv(ioc->sh); - if (!hd->ioc) - goto out; - - if (list_empty(&hd->target_reset_list)) - goto out; - - /* flush the target_reset_list */ - list_for_each_entry_safe(target_reset_list, n, - &hd->target_reset_list, list) { - list_del(&target_reset_list->list); - kfree(target_reset_list); + switch(reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->sas_mgmt.done); + } + hd = shost_priv(ioc->sh); + if (!hd->ioc) + goto out; + if (list_empty(&hd->target_reset_list)) + break; + /* flush the target_reset_list */ + list_for_each_entry_safe(target_reset_list, n, + &hd->target_reset_list, list) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: removing target reset for id=%d\n", + ioc->name, __FUNCTION__, + target_reset_list->sas_event_data.TargetID)); + list_del(&target_reset_list->list); + kfree(target_reset_list); + } + break; + default: + break; } out: @@ -861,9 +876,14 @@ mptsas_target_alloc(struct scsi_target * * RAID volumes placed beyond the last expected port. */ if (starget->channel == MPTSAS_RAID_CHANNEL) { + if (!ioc->raid_data.pIocPg2) { + kfree(vtarget); + return -ENXIO; + } for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + vtarget->raidVolume = 1; goto out; } @@ -1100,14 +1120,19 @@ static int mptsas_get_linkerrors(struct static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; if (reply != NULL) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; memcpy(ioc->sas_mgmt.reply, reply, min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); } - complete(&ioc->sas_mgmt.done); - return 1; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->sas_mgmt.done); + return 1; + } + return 0; } static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) @@ -1146,21 +1171,24 @@ static int mptsas_phy_reset(struct sas_p MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; req->PhyNum = phy->identify.phy_identifier; + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); - - timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, - 10 * HZ); - if (!timeleft) { - /* On timeout reset the board */ + timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10*HZ); + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + error = -ETIME; mpt_free_msg_frame(ioc, mf); - mpt_HardResetHandler(ioc, CAN_SLEEP); - error = -ETIMEDOUT; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } goto out_unlock; } /* a reply frame is expected */ if ((ioc->sas_mgmt.status & - MPT_IOCTL_STATUS_RF_VALID) == 0) { + MPT_MGMT_STATUS_RF_VALID) == 0) { error = -ENXIO; goto out_unlock; } @@ -1177,6 +1205,7 @@ static int mptsas_phy_reset(struct sas_p error = 0; out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) mutex_unlock(&ioc->sas_mgmt.mutex); out: return error; @@ -1325,19 +1354,24 @@ static int mptsas_smp_handler(struct Scs goto unmap; mpt_add_sge(psge, flagsLength, dma_addr_in); + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); - timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); - if (!timeleft) { - printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__); - /* On timeout reset the board */ - mpt_HardResetHandler(ioc, CAN_SLEEP); - ret = -ETIMEDOUT; + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } goto unmap; } + mf = NULL; - if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) { + if ((ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) == 0) { SmpPassthroughReply_t *smprep; smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; @@ -1349,6 +1383,7 @@ static int mptsas_smp_handler(struct Scs ret = -ENXIO; } unmap: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) if (dma_addr_out) pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, PCI_DMA_BIDIRECTIONAL); @@ -3232,32 +3267,8 @@ mptsas_probe(struct pci_dev *pdev, const dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - ioc->sas_data.ptClear = mpt_pt_clear; - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; INIT_LIST_HEAD(&hd->target_reset_list); spin_unlock_irqrestore(&ioc->FreeQlock, flags); - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html