diff options
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 484 |
1 files changed, 291 insertions, 193 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 32f8dac6abfe..caaa209feca3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
| @@ -2676,72 +2676,6 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, | |||
| 2676 | } | 2676 | } |
| 2677 | 2677 | ||
| 2678 | /** | 2678 | /** |
| 2679 | * lpfc_scsi_tgt_reset - Target reset handler | ||
| 2680 | * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure | ||
| 2681 | * @vport: The virtual port for which this call is being executed. | ||
| 2682 | * @tgt_id: Target ID. | ||
| 2683 | * @lun: Lun number. | ||
| 2684 | * @rdata: Pointer to lpfc_rport_data. | ||
| 2685 | * | ||
| 2686 | * This routine issues a TARGET RESET iocb to reset a target with @tgt_id ID. | ||
| 2687 | * | ||
| 2688 | * Return Code: | ||
| 2689 | * 0x2003 - Error | ||
| 2690 | * 0x2002 - Success. | ||
| 2691 | **/ | ||
| 2692 | static int | ||
| 2693 | lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, | ||
| 2694 | unsigned tgt_id, unsigned int lun, | ||
| 2695 | struct lpfc_rport_data *rdata) | ||
| 2696 | { | ||
| 2697 | struct lpfc_hba *phba = vport->phba; | ||
| 2698 | struct lpfc_iocbq *iocbq; | ||
| 2699 | struct lpfc_iocbq *iocbqrsp; | ||
| 2700 | int ret; | ||
| 2701 | int status; | ||
| 2702 | |||
| 2703 | if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) | ||
| 2704 | return FAILED; | ||
| 2705 | |||
| 2706 | lpfc_cmd->rdata = rdata; | ||
| 2707 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, | ||
| 2708 | FCP_TARGET_RESET); | ||
| 2709 | if (!status) | ||
| 2710 | return FAILED; | ||
| 2711 | |||
| 2712 | iocbq = &lpfc_cmd->cur_iocbq; | ||
| 2713 | iocbqrsp = lpfc_sli_get_iocbq(phba); | ||
| 2714 | |||
| 2715 | if (!iocbqrsp) | ||
| 2716 | return FAILED; | ||
| 2717 | |||
| 2718 | /* Issue Target Reset to TGT <num> */ | ||
| 2719 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
| 2720 | "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", | ||
| 2721 | tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); | ||
| 2722 | status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, | ||
| 2723 | iocbq, iocbqrsp, lpfc_cmd->timeout); | ||
| 2724 | if (status != IOCB_SUCCESS) { | ||
| 2725 | if (status == IOCB_TIMEDOUT) { | ||
| 2726 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | ||
| 2727 | ret = TIMEOUT_ERROR; | ||
| 2728 | } else | ||
| 2729 | ret = FAILED; | ||
| 2730 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | ||
| 2731 | } else { | ||
| 2732 | ret = SUCCESS; | ||
| 2733 | lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; | ||
| 2734 | lpfc_cmd->status = iocbqrsp->iocb.ulpStatus; | ||
| 2735 | if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && | ||
| 2736 | (lpfc_cmd->result & IOERR_DRVR_MASK)) | ||
| 2737 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | ||
| 2738 | } | ||
| 2739 | |||
| 2740 | lpfc_sli_release_iocbq(phba, iocbqrsp); | ||
| 2741 | return ret; | ||
| 2742 | } | ||
| 2743 | |||
| 2744 | /** | ||
| 2745 | * lpfc_info - Info entry point of scsi_host_template data structure | 2679 | * lpfc_info - Info entry point of scsi_host_template data structure |
| 2746 | * @host: The scsi host for which this call is being executed. | 2680 | * @host: The scsi host for which this call is being executed. |
| 2747 | * | 2681 | * |
| @@ -3121,156 +3055,334 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) | |||
| 3121 | return ret; | 3055 | return ret; |
| 3122 | } | 3056 | } |
| 3123 | 3057 | ||
| 3058 | static char * | ||
| 3059 | lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) | ||
| 3060 | { | ||
| 3061 | switch (task_mgmt_cmd) { | ||
| 3062 | case FCP_ABORT_TASK_SET: | ||
| 3063 | return "ABORT_TASK_SET"; | ||
| 3064 | case FCP_CLEAR_TASK_SET: | ||
| 3065 | return "FCP_CLEAR_TASK_SET"; | ||
| 3066 | case FCP_BUS_RESET: | ||
| 3067 | return "FCP_BUS_RESET"; | ||
| 3068 | case FCP_LUN_RESET: | ||
| 3069 | return "FCP_LUN_RESET"; | ||
| 3070 | case FCP_TARGET_RESET: | ||
| 3071 | return "FCP_TARGET_RESET"; | ||
| 3072 | case FCP_CLEAR_ACA: | ||
| 3073 | return "FCP_CLEAR_ACA"; | ||
| 3074 | case FCP_TERMINATE_TASK: | ||
| 3075 | return "FCP_TERMINATE_TASK"; | ||
| 3076 | default: | ||
| 3077 | return "unknown"; | ||
| 3078 | } | ||
| 3079 | } | ||
| 3080 | |||
| 3124 | /** | 3081 | /** |
| 3125 | * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point | 3082 | * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler |
| 3126 | * @cmnd: Pointer to scsi_cmnd data structure. | 3083 | * @vport: The virtual port for which this call is being executed. |
| 3084 | * @rdata: Pointer to remote port local data | ||
| 3085 | * @tgt_id: Target ID of remote device. | ||
| 3086 | * @lun_id: Lun number for the TMF | ||
| 3087 | * @task_mgmt_cmd: type of TMF to send | ||
| 3127 | * | 3088 | * |
| 3128 | * This routine does a device reset by sending a TARGET_RESET task management | 3089 | * This routine builds and sends a TMF (SCSI Task Mgmt Function) to |
| 3129 | * command. | 3090 | * a remote port. |
| 3130 | * | 3091 | * |
| 3131 | * Return code : | 3092 | * Return Code: |
| 3132 | * 0x2003 - Error | 3093 | * 0x2003 - Error |
| 3133 | * 0x2002 - Success | 3094 | * 0x2002 - Success. |
| 3134 | **/ | 3095 | **/ |
| 3135 | static int | 3096 | static int |
| 3136 | lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | 3097 | lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, |
| 3098 | unsigned tgt_id, unsigned int lun_id, | ||
| 3099 | uint8_t task_mgmt_cmd) | ||
| 3137 | { | 3100 | { |
| 3138 | struct Scsi_Host *shost = cmnd->device->host; | ||
| 3139 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||
| 3140 | struct lpfc_hba *phba = vport->phba; | 3101 | struct lpfc_hba *phba = vport->phba; |
| 3141 | struct lpfc_scsi_buf *lpfc_cmd; | 3102 | struct lpfc_scsi_buf *lpfc_cmd; |
| 3142 | struct lpfc_iocbq *iocbq, *iocbqrsp; | 3103 | struct lpfc_iocbq *iocbq; |
| 3143 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 3104 | struct lpfc_iocbq *iocbqrsp; |
| 3144 | struct lpfc_nodelist *pnode = rdata->pnode; | 3105 | int ret; |
| 3145 | unsigned long later; | ||
| 3146 | int ret = SUCCESS; | ||
| 3147 | int status; | 3106 | int status; |
| 3148 | int cnt; | ||
| 3149 | struct lpfc_scsi_event_header scsi_event; | ||
| 3150 | |||
| 3151 | lpfc_block_error_handler(cmnd); | ||
| 3152 | /* | ||
| 3153 | * If target is not in a MAPPED state, delay the reset until | ||
| 3154 | * target is rediscovered or devloss timeout expires. | ||
| 3155 | */ | ||
| 3156 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; | ||
| 3157 | while (time_after(later, jiffies)) { | ||
| 3158 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) | ||
| 3159 | return FAILED; | ||
| 3160 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) | ||
| 3161 | break; | ||
| 3162 | schedule_timeout_uninterruptible(msecs_to_jiffies(500)); | ||
| 3163 | rdata = cmnd->device->hostdata; | ||
| 3164 | if (!rdata) | ||
| 3165 | break; | ||
| 3166 | pnode = rdata->pnode; | ||
| 3167 | } | ||
| 3168 | 3107 | ||
| 3169 | scsi_event.event_type = FC_REG_SCSI_EVENT; | 3108 | if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) |
| 3170 | scsi_event.subcategory = LPFC_EVENT_TGTRESET; | ||
| 3171 | scsi_event.lun = 0; | ||
| 3172 | memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); | ||
| 3173 | memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); | ||
| 3174 | |||
| 3175 | fc_host_post_vendor_event(shost, | ||
| 3176 | fc_get_event_number(), | ||
| 3177 | sizeof(scsi_event), | ||
| 3178 | (char *)&scsi_event, | ||
| 3179 | LPFC_NL_VENDOR_ID); | ||
| 3180 | |||
| 3181 | if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { | ||
| 3182 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
| 3183 | "0721 LUN Reset rport " | ||
| 3184 | "failure: msec x%x rdata x%p\n", | ||
| 3185 | jiffies_to_msecs(jiffies - later), rdata); | ||
| 3186 | return FAILED; | 3109 | return FAILED; |
| 3187 | } | 3110 | |
| 3188 | lpfc_cmd = lpfc_get_scsi_buf(phba); | 3111 | lpfc_cmd = lpfc_get_scsi_buf(phba); |
| 3189 | if (lpfc_cmd == NULL) | 3112 | if (lpfc_cmd == NULL) |
| 3190 | return FAILED; | 3113 | return FAILED; |
| 3191 | lpfc_cmd->timeout = 60; | 3114 | lpfc_cmd->timeout = 60; |
| 3192 | lpfc_cmd->rdata = rdata; | 3115 | lpfc_cmd->rdata = rdata; |
| 3193 | 3116 | ||
| 3194 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, | 3117 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id, |
| 3195 | cmnd->device->lun, | 3118 | task_mgmt_cmd); |
| 3196 | FCP_TARGET_RESET); | ||
| 3197 | if (!status) { | 3119 | if (!status) { |
| 3198 | lpfc_release_scsi_buf(phba, lpfc_cmd); | 3120 | lpfc_release_scsi_buf(phba, lpfc_cmd); |
| 3199 | return FAILED; | 3121 | return FAILED; |
| 3200 | } | 3122 | } |
| 3201 | iocbq = &lpfc_cmd->cur_iocbq; | ||
| 3202 | 3123 | ||
| 3203 | /* get a buffer for this IOCB command response */ | 3124 | iocbq = &lpfc_cmd->cur_iocbq; |
| 3204 | iocbqrsp = lpfc_sli_get_iocbq(phba); | 3125 | iocbqrsp = lpfc_sli_get_iocbq(phba); |
| 3205 | if (iocbqrsp == NULL) { | 3126 | if (iocbqrsp == NULL) { |
| 3206 | lpfc_release_scsi_buf(phba, lpfc_cmd); | 3127 | lpfc_release_scsi_buf(phba, lpfc_cmd); |
| 3207 | return FAILED; | 3128 | return FAILED; |
| 3208 | } | 3129 | } |
| 3130 | |||
| 3209 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | 3131 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, |
| 3210 | "0703 Issue target reset to TGT %d LUN %d " | 3132 | "0702 Issue %s to TGT %d LUN %d " |
| 3211 | "rpi x%x nlp_flag x%x\n", cmnd->device->id, | 3133 | "rpi x%x nlp_flag x%x\n", |
| 3212 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); | 3134 | lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, |
| 3135 | rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); | ||
| 3136 | |||
| 3213 | status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, | 3137 | status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, |
| 3214 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 3138 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
| 3215 | if (status == IOCB_TIMEDOUT) { | 3139 | if (status != IOCB_SUCCESS) { |
| 3216 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | 3140 | if (status == IOCB_TIMEDOUT) { |
| 3217 | ret = TIMEOUT_ERROR; | 3141 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; |
| 3218 | } else { | 3142 | ret = TIMEOUT_ERROR; |
| 3219 | if (status != IOCB_SUCCESS) | 3143 | } else |
| 3220 | ret = FAILED; | 3144 | ret = FAILED; |
| 3221 | lpfc_release_scsi_buf(phba, lpfc_cmd); | 3145 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; |
| 3222 | } | 3146 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
| 3223 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 3147 | "0727 TMF %s to TGT %d LUN %d failed (%d, %d)\n", |
| 3224 | "0713 SCSI layer issued device reset (%d, %d) " | 3148 | lpfc_taskmgmt_name(task_mgmt_cmd), |
| 3225 | "return x%x status x%x result x%x\n", | 3149 | tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, |
| 3226 | cmnd->device->id, cmnd->device->lun, ret, | ||
| 3227 | iocbqrsp->iocb.ulpStatus, | ||
| 3228 | iocbqrsp->iocb.un.ulpWord[4]); | 3150 | iocbqrsp->iocb.un.ulpWord[4]); |
| 3151 | } else | ||
| 3152 | ret = SUCCESS; | ||
| 3153 | |||
| 3229 | lpfc_sli_release_iocbq(phba, iocbqrsp); | 3154 | lpfc_sli_release_iocbq(phba, iocbqrsp); |
| 3230 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, | 3155 | |
| 3231 | LPFC_CTX_TGT); | 3156 | if (ret != TIMEOUT_ERROR) |
| 3157 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
| 3158 | |||
| 3159 | return ret; | ||
| 3160 | } | ||
| 3161 | |||
| 3162 | /** | ||
| 3163 | * lpfc_chk_tgt_mapped - | ||
| 3164 | * @vport: The virtual port to check on | ||
| 3165 | * @cmnd: Pointer to scsi_cmnd data structure. | ||
| 3166 | * | ||
| 3167 | * This routine delays until the scsi target (aka rport) for the | ||
| 3168 | * command exists (is present and logged in) or we declare it non-existent. | ||
| 3169 | * | ||
| 3170 | * Return code : | ||
| 3171 | * 0x2003 - Error | ||
| 3172 | * 0x2002 - Success | ||
| 3173 | **/ | ||
| 3174 | static int | ||
| 3175 | lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) | ||
| 3176 | { | ||
| 3177 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | ||
| 3178 | struct lpfc_nodelist *pnode = rdata->pnode; | ||
| 3179 | unsigned long later; | ||
| 3180 | |||
| 3181 | /* | ||
| 3182 | * If target is not in a MAPPED state, delay until | ||
| 3183 | * target is rediscovered or devloss timeout expires. | ||
| 3184 | */ | ||
| 3185 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; | ||
| 3186 | while (time_after(later, jiffies)) { | ||
| 3187 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) | ||
| 3188 | return FAILED; | ||
| 3189 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) | ||
| 3190 | return SUCCESS; | ||
| 3191 | schedule_timeout_uninterruptible(msecs_to_jiffies(500)); | ||
| 3192 | rdata = cmnd->device->hostdata; | ||
| 3193 | if (!rdata) | ||
| 3194 | return FAILED; | ||
| 3195 | pnode = rdata->pnode; | ||
| 3196 | } | ||
| 3197 | if (!pnode || !NLP_CHK_NODE_ACT(pnode) || | ||
| 3198 | (pnode->nlp_state != NLP_STE_MAPPED_NODE)) | ||
| 3199 | return FAILED; | ||
| 3200 | return SUCCESS; | ||
| 3201 | } | ||
| 3202 | |||
| 3203 | /** | ||
| 3204 | * lpfc_reset_flush_io_context - | ||
| 3205 | * @vport: The virtual port (scsi_host) for the flush context | ||
| 3206 | * @tgt_id: If aborting by Target contect - specifies the target id | ||
| 3207 | * @lun_id: If aborting by Lun context - specifies the lun id | ||
| 3208 | * @context: specifies the context level to flush at. | ||
| 3209 | * | ||
| 3210 | * After a reset condition via TMF, we need to flush orphaned i/o | ||
| 3211 | * contexts from the adapter. This routine aborts any contexts | ||
| 3212 | * outstanding, then waits for their completions. The wait is | ||
| 3213 | * bounded by devloss_tmo though. | ||
| 3214 | * | ||
| 3215 | * Return code : | ||
| 3216 | * 0x2003 - Error | ||
| 3217 | * 0x2002 - Success | ||
| 3218 | **/ | ||
| 3219 | static int | ||
| 3220 | lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, | ||
| 3221 | uint64_t lun_id, lpfc_ctx_cmd context) | ||
| 3222 | { | ||
| 3223 | struct lpfc_hba *phba = vport->phba; | ||
| 3224 | unsigned long later; | ||
| 3225 | int cnt; | ||
| 3226 | |||
| 3227 | cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); | ||
| 3232 | if (cnt) | 3228 | if (cnt) |
| 3233 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 3229 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], |
| 3234 | cmnd->device->id, cmnd->device->lun, | 3230 | tgt_id, lun_id, context); |
| 3235 | LPFC_CTX_TGT); | ||
| 3236 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; | 3231 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
| 3237 | while (time_after(later, jiffies) && cnt) { | 3232 | while (time_after(later, jiffies) && cnt) { |
| 3238 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); | 3233 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); |
| 3239 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, | 3234 | cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); |
| 3240 | cmnd->device->lun, LPFC_CTX_TGT); | ||
| 3241 | } | 3235 | } |
| 3242 | if (cnt) { | 3236 | if (cnt) { |
| 3243 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 3237 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
| 3244 | "0719 device reset I/O flush failure: " | 3238 | "0724 I/O flush failure for context %s : cnt x%x\n", |
| 3245 | "cnt x%x\n", cnt); | 3239 | ((context == LPFC_CTX_LUN) ? "LUN" : |
| 3246 | ret = FAILED; | 3240 | ((context == LPFC_CTX_TGT) ? "TGT" : |
| 3241 | ((context == LPFC_CTX_HOST) ? "HOST" : "Unknown"))), | ||
| 3242 | cnt); | ||
| 3243 | return FAILED; | ||
| 3247 | } | 3244 | } |
| 3248 | return ret; | 3245 | return SUCCESS; |
| 3246 | } | ||
| 3247 | |||
| 3248 | /** | ||
| 3249 | * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point | ||
| 3250 | * @cmnd: Pointer to scsi_cmnd data structure. | ||
| 3251 | * | ||
| 3252 | * This routine does a device reset by sending a LUN_RESET task management | ||
| 3253 | * command. | ||
| 3254 | * | ||
| 3255 | * Return code : | ||
| 3256 | * 0x2003 - Error | ||
| 3257 | * 0x2002 - Success | ||
| 3258 | **/ | ||
| 3259 | static int | ||
| 3260 | lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | ||
| 3261 | { | ||
| 3262 | struct Scsi_Host *shost = cmnd->device->host; | ||
| 3263 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||
| 3264 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | ||
| 3265 | struct lpfc_nodelist *pnode = rdata->pnode; | ||
| 3266 | unsigned tgt_id = cmnd->device->id; | ||
| 3267 | unsigned int lun_id = cmnd->device->lun; | ||
| 3268 | struct lpfc_scsi_event_header scsi_event; | ||
| 3269 | int status; | ||
| 3270 | |||
| 3271 | lpfc_block_error_handler(cmnd); | ||
| 3272 | |||
| 3273 | status = lpfc_chk_tgt_mapped(vport, cmnd); | ||
| 3274 | if (status == FAILED) { | ||
| 3275 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
| 3276 | "0721 Device Reset rport failure: rdata x%p\n", rdata); | ||
| 3277 | return FAILED; | ||
| 3278 | } | ||
| 3279 | |||
| 3280 | scsi_event.event_type = FC_REG_SCSI_EVENT; | ||
| 3281 | scsi_event.subcategory = LPFC_EVENT_LUNRESET; | ||
| 3282 | scsi_event.lun = lun_id; | ||
| 3283 | memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); | ||
| 3284 | memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); | ||
| 3285 | |||
| 3286 | fc_host_post_vendor_event(shost, fc_get_event_number(), | ||
| 3287 | sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); | ||
| 3288 | |||
| 3289 | status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, | ||
| 3290 | FCP_LUN_RESET); | ||
| 3291 | |||
| 3292 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
| 3293 | "0713 SCSI layer issued Device Reset (%d, %d) " | ||
| 3294 | "return x%x\n", tgt_id, lun_id, status); | ||
| 3295 | |||
| 3296 | /* | ||
| 3297 | * We have to clean up i/o as : they may be orphaned by the TMF; | ||
| 3298 | * or if the TMF failed, they may be in an indeterminate state. | ||
| 3299 | * So, continue on. | ||
| 3300 | * We will report success if all the i/o aborts successfully. | ||
| 3301 | */ | ||
| 3302 | status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, | ||
| 3303 | LPFC_CTX_LUN); | ||
| 3304 | return status; | ||
| 3305 | } | ||
| 3306 | |||
| 3307 | /** | ||
| 3308 | * lpfc_target_reset_handler - scsi_host_template eh_target_reset entry point | ||
| 3309 | * @cmnd: Pointer to scsi_cmnd data structure. | ||
| 3310 | * | ||
| 3311 | * This routine does a target reset by sending a TARGET_RESET task management | ||
| 3312 | * command. | ||
| 3313 | * | ||
| 3314 | * Return code : | ||
| 3315 | * 0x2003 - Error | ||
| 3316 | * 0x2002 - Success | ||
| 3317 | **/ | ||
| 3318 | static int | ||
| 3319 | lpfc_target_reset_handler(struct scsi_cmnd *cmnd) | ||
| 3320 | { | ||
| 3321 | struct Scsi_Host *shost = cmnd->device->host; | ||
| 3322 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||
| 3323 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | ||
| 3324 | struct lpfc_nodelist *pnode = rdata->pnode; | ||
| 3325 | unsigned tgt_id = cmnd->device->id; | ||
| 3326 | unsigned int lun_id = cmnd->device->lun; | ||
| 3327 | struct lpfc_scsi_event_header scsi_event; | ||
| 3328 | int status; | ||
| 3329 | |||
| 3330 | lpfc_block_error_handler(cmnd); | ||
| 3331 | |||
| 3332 | status = lpfc_chk_tgt_mapped(vport, cmnd); | ||
| 3333 | if (status == FAILED) { | ||
| 3334 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
| 3335 | "0722 Target Reset rport failure: rdata x%p\n", rdata); | ||
| 3336 | return FAILED; | ||
| 3337 | } | ||
| 3338 | |||
| 3339 | scsi_event.event_type = FC_REG_SCSI_EVENT; | ||
| 3340 | scsi_event.subcategory = LPFC_EVENT_TGTRESET; | ||
| 3341 | scsi_event.lun = 0; | ||
| 3342 | memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); | ||
| 3343 | memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); | ||
| 3344 | |||
| 3345 | fc_host_post_vendor_event(shost, fc_get_event_number(), | ||
| 3346 | sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); | ||
| 3347 | |||
| 3348 | status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, | ||
| 3349 | FCP_TARGET_RESET); | ||
| 3350 | |||
| 3351 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
| 3352 | "0723 SCSI layer issued Target Reset (%d, %d) " | ||
| 3353 | "return x%x\n", tgt_id, lun_id, status); | ||
| 3354 | |||
| 3355 | /* | ||
| 3356 | * We have to clean up i/o as : they may be orphaned by the TMF; | ||
| 3357 | * or if the TMF failed, they may be in an indeterminate state. | ||
| 3358 | * So, continue on. | ||
| 3359 | * We will report success if all the i/o aborts successfully. | ||
| 3360 | */ | ||
| 3361 | status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, | ||
| 3362 | LPFC_CTX_TGT); | ||
| 3363 | return status; | ||
| 3249 | } | 3364 | } |
| 3250 | 3365 | ||
| 3251 | /** | 3366 | /** |
| 3252 | * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point | 3367 | * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point |
| 3253 | * @cmnd: Pointer to scsi_cmnd data structure. | 3368 | * @cmnd: Pointer to scsi_cmnd data structure. |
| 3254 | * | 3369 | * |
| 3255 | * This routine does target reset to all target on @cmnd->device->host. | 3370 | * This routine does target reset to all targets on @cmnd->device->host. |
| 3371 | * This emulates Parallel SCSI Bus Reset Semantics. | ||
| 3256 | * | 3372 | * |
| 3257 | * Return Code: | 3373 | * Return code : |
| 3258 | * 0x2003 - Error | 3374 | * 0x2003 - Error |
| 3259 | * 0x2002 - Success | 3375 | * 0x2002 - Success |
| 3260 | **/ | 3376 | **/ |
| 3261 | static int | 3377 | static int |
| 3262 | lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | 3378 | lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) |
| 3263 | { | 3379 | { |
| 3264 | struct Scsi_Host *shost = cmnd->device->host; | 3380 | struct Scsi_Host *shost = cmnd->device->host; |
| 3265 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 3381 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
| 3266 | struct lpfc_hba *phba = vport->phba; | ||
| 3267 | struct lpfc_nodelist *ndlp = NULL; | 3382 | struct lpfc_nodelist *ndlp = NULL; |
| 3268 | int match; | ||
| 3269 | int ret = SUCCESS, status = SUCCESS, i; | ||
| 3270 | int cnt; | ||
| 3271 | struct lpfc_scsi_buf * lpfc_cmd; | ||
| 3272 | unsigned long later; | ||
| 3273 | struct lpfc_scsi_event_header scsi_event; | 3383 | struct lpfc_scsi_event_header scsi_event; |
| 3384 | int match; | ||
| 3385 | int ret = SUCCESS, status, i; | ||
| 3274 | 3386 | ||
| 3275 | scsi_event.event_type = FC_REG_SCSI_EVENT; | 3387 | scsi_event.event_type = FC_REG_SCSI_EVENT; |
| 3276 | scsi_event.subcategory = LPFC_EVENT_BUSRESET; | 3388 | scsi_event.subcategory = LPFC_EVENT_BUSRESET; |
| @@ -3278,13 +3390,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
| 3278 | memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); | 3390 | memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); |
| 3279 | memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); | 3391 | memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); |
| 3280 | 3392 | ||
| 3281 | fc_host_post_vendor_event(shost, | 3393 | fc_host_post_vendor_event(shost, fc_get_event_number(), |
| 3282 | fc_get_event_number(), | 3394 | sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); |
| 3283 | sizeof(scsi_event), | ||
| 3284 | (char *)&scsi_event, | ||
| 3285 | LPFC_NL_VENDOR_ID); | ||
| 3286 | 3395 | ||
| 3287 | lpfc_block_error_handler(cmnd); | 3396 | lpfc_block_error_handler(cmnd); |
| 3397 | |||
| 3288 | /* | 3398 | /* |
| 3289 | * Since the driver manages a single bus device, reset all | 3399 | * Since the driver manages a single bus device, reset all |
| 3290 | * targets known to the driver. Should any target reset | 3400 | * targets known to the driver. Should any target reset |
| @@ -3307,16 +3417,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
| 3307 | spin_unlock_irq(shost->host_lock); | 3417 | spin_unlock_irq(shost->host_lock); |
| 3308 | if (!match) | 3418 | if (!match) |
| 3309 | continue; | 3419 | continue; |
| 3310 | lpfc_cmd = lpfc_get_scsi_buf(phba); | 3420 | |
| 3311 | if (lpfc_cmd) { | 3421 | status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data, |
| 3312 | lpfc_cmd->timeout = 60; | 3422 | i, 0, FCP_TARGET_RESET); |
| 3313 | status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, | 3423 | |
| 3314 | cmnd->device->lun, | 3424 | if (status != SUCCESS) { |
| 3315 | ndlp->rport->dd_data); | ||
| 3316 | if (status != TIMEOUT_ERROR) | ||
| 3317 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
| 3318 | } | ||
| 3319 | if (!lpfc_cmd || status != SUCCESS) { | ||
| 3320 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 3425 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
| 3321 | "0700 Bus Reset on target %d failed\n", | 3426 | "0700 Bus Reset on target %d failed\n", |
| 3322 | i); | 3427 | i); |
| @@ -3324,25 +3429,16 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
| 3324 | } | 3429 | } |
| 3325 | } | 3430 | } |
| 3326 | /* | 3431 | /* |
| 3327 | * All outstanding txcmplq I/Os should have been aborted by | 3432 | * We have to clean up i/o as : they may be orphaned by the TMFs |
| 3328 | * the targets. Unfortunately, some targets do not abide by | 3433 | * above; or if any of the TMFs failed, they may be in an |
| 3329 | * this forcing the driver to double check. | 3434 | * indeterminate state. |
| 3435 | * We will report success if all the i/o aborts successfully. | ||
| 3330 | */ | 3436 | */ |
| 3331 | cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); | 3437 | |
| 3332 | if (cnt) | 3438 | status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST); |
| 3333 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 3439 | if (status != SUCCESS) |
| 3334 | 0, 0, LPFC_CTX_HOST); | ||
| 3335 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; | ||
| 3336 | while (time_after(later, jiffies) && cnt) { | ||
| 3337 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); | ||
| 3338 | cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); | ||
| 3339 | } | ||
| 3340 | if (cnt) { | ||
| 3341 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
| 3342 | "0715 Bus Reset I/O flush failure: " | ||
| 3343 | "cnt x%x left x%x\n", cnt, i); | ||
| 3344 | ret = FAILED; | 3440 | ret = FAILED; |
| 3345 | } | 3441 | |
| 3346 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 3442 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
| 3347 | "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); | 3443 | "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); |
| 3348 | return ret; | 3444 | return ret; |
| @@ -3475,7 +3571,8 @@ struct scsi_host_template lpfc_template = { | |||
| 3475 | .info = lpfc_info, | 3571 | .info = lpfc_info, |
| 3476 | .queuecommand = lpfc_queuecommand, | 3572 | .queuecommand = lpfc_queuecommand, |
| 3477 | .eh_abort_handler = lpfc_abort_handler, | 3573 | .eh_abort_handler = lpfc_abort_handler, |
| 3478 | .eh_device_reset_handler= lpfc_device_reset_handler, | 3574 | .eh_device_reset_handler = lpfc_device_reset_handler, |
| 3575 | .eh_target_reset_handler = lpfc_target_reset_handler, | ||
| 3479 | .eh_bus_reset_handler = lpfc_bus_reset_handler, | 3576 | .eh_bus_reset_handler = lpfc_bus_reset_handler, |
| 3480 | .slave_alloc = lpfc_slave_alloc, | 3577 | .slave_alloc = lpfc_slave_alloc, |
| 3481 | .slave_configure = lpfc_slave_configure, | 3578 | .slave_configure = lpfc_slave_configure, |
| @@ -3495,7 +3592,8 @@ struct scsi_host_template lpfc_vport_template = { | |||
| 3495 | .info = lpfc_info, | 3592 | .info = lpfc_info, |
| 3496 | .queuecommand = lpfc_queuecommand, | 3593 | .queuecommand = lpfc_queuecommand, |
| 3497 | .eh_abort_handler = lpfc_abort_handler, | 3594 | .eh_abort_handler = lpfc_abort_handler, |
| 3498 | .eh_device_reset_handler= lpfc_device_reset_handler, | 3595 | .eh_device_reset_handler = lpfc_device_reset_handler, |
| 3596 | .eh_target_reset_handler = lpfc_target_reset_handler, | ||
| 3499 | .eh_bus_reset_handler = lpfc_bus_reset_handler, | 3597 | .eh_bus_reset_handler = lpfc_bus_reset_handler, |
| 3500 | .slave_alloc = lpfc_slave_alloc, | 3598 | .slave_alloc = lpfc_slave_alloc, |
| 3501 | .slave_configure = lpfc_slave_configure, | 3599 | .slave_configure = lpfc_slave_configure, |
