diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 17:43:10 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 17:43:10 -0800 |
commit | 590cf28580c999c8ba70dc39b40bab09d69e2630 (patch) | |
tree | 22b9aa4b148bea8a310b760521d1032eef7d743f /drivers/scsi/ibmvscsi | |
parent | f54a6ec0fd85002d94d05b4bb679508eeb066683 (diff) | |
parent | fb5edd020fa0fbe991f4a473611ad530d2237425 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (104 commits)
[SCSI] fcoe: fix configuration problems
[SCSI] cxgb3i: fix select/depend problem
[SCSI] fcoe: fix incorrect use of struct module
[SCSI] cxgb3i: remove use of skb->sp
[SCSI] cxgb3i: Add cxgb3i iSCSI driver.
[SCSI] zfcp: Remove unnecessary warning message
[SCSI] zfcp: Add support for unchained FSF requests
[SCSI] zfcp: Remove busid macro
[SCSI] zfcp: remove DID_DID flag
[SCSI] zfcp: Simplify mask lookups for incoming RSCNs
[SCSI] zfcp: Remove initial device data from zfcp_data
[SCSI] zfcp: fix compile warning
[SCSI] zfcp: Remove adapter list
[SCSI] zfcp: Simplify SBAL allocation to fix sparse warnings
[SCSI] zfcp: register with SCSI layer on ccw registration
[SCSI] zfcp: Fix message line break
[SCSI] qla2xxx: changes in multiq code
[SCSI] eata: fix the data buffer accessors conversion regression
[SCSI] ibmvfc: Improve async event handling
[SCSI] lpfc : correct printk types on PPC compiles
...
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.c | 293 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvfc.h | 32 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.c | 4 |
3 files changed, 216 insertions, 113 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 7650707a40d..44f202f3310 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -121,6 +121,7 @@ static const struct { { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, @@ -278,13 +279,6 @@ static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) rsp->data.info.rsp_code)) return DID_ERROR << 16; - if (!vfc_cmd->status) { - if (rsp->flags & FCP_RESID_OVER) - return rsp->scsi_status | (DID_ERROR << 16); - else - return rsp->scsi_status | (DID_OK << 16); - } - err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); if (err >= 0) return rsp->scsi_status | (cmd_status[err].result << 16); @@ -503,6 +497,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_QUERY_TGTS: + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_TGT_ADD: case IBMVFC_HOST_ACTION_NONE: default: @@ -566,7 +561,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin) struct ibmvfc_target *tgt; if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { - if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { + if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { dev_err(vhost->dev, "Host initialization retries exceeded. Taking adapter offline\n"); ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); @@ -765,6 +760,9 @@ static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt) cmnd->scsi_done(cmnd); } + if (evt->eh_comp) + complete(evt->eh_comp); + ibmvfc_free_event(evt); } @@ -847,11 +845,12 @@ static void ibmvfc_reset_host(struct ibmvfc_host *vhost) static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) { if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { - if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { + vhost->delay_init = 1; + if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { dev_err(vhost->dev, "Host initialization retries exceeded. Taking adapter offline\n"); ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); - } else if (vhost->init_retries == IBMVFC_MAX_INIT_RETRIES) + } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES) __ibmvfc_reset_host(vhost); else ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); @@ -1252,6 +1251,7 @@ static void ibmvfc_init_event(struct ibmvfc_event *evt, evt->sync_iu = NULL; evt->crq.format = format; evt->done = done; + evt->eh_comp = NULL; } /** @@ -1381,6 +1381,8 @@ static int ibmvfc_send_event(struct ibmvfc_event *evt, add_timer(&evt->timer); } + mb(); + if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { list_del(&evt->queue); del_timer(&evt->timer); @@ -1477,6 +1479,11 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt) sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); + if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) + ibmvfc_reinit_host(evt->vhost); + + if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) + cmnd->result = (DID_ERROR << 16); ibmvfc_log_error(evt); } @@ -1489,6 +1496,9 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt) cmnd->scsi_done(cmnd); } + if (evt->eh_comp) + complete(evt->eh_comp); + ibmvfc_free_event(evt); } @@ -1627,7 +1637,7 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) struct ibmvfc_host *vhost = shost_priv(sdev->host); struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); struct ibmvfc_cmd *tmf; - struct ibmvfc_event *evt; + struct ibmvfc_event *evt = NULL; union ibmvfc_iu rsp_iu; struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; int rsp_rc = -EBUSY; @@ -1789,7 +1799,8 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev) static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) { struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct scsi_target *starget = scsi_target(sdev); + struct fc_rport *rport = starget_to_rport(starget); struct ibmvfc_tmf *tmf; struct ibmvfc_event *evt, *found_evt; union ibmvfc_iu rsp; @@ -1827,7 +1838,7 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) int_to_scsilun(sdev->lun, &tmf->lun); tmf->flags = (type | IBMVFC_TMF_LUA_VALID); tmf->cancel_key = (unsigned long)sdev->hostdata; - tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata); + tmf->my_cancel_key = (unsigned long)starget->hostdata; evt->sync_iu = &rsp; init_completion(&evt->comp); @@ -1859,6 +1870,91 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) } /** + * ibmvfc_match_target - Match function for specified target + * @evt: ibmvfc event struct + * @device: device to match (starget) + * + * Returns: + * 1 if event matches starget / 0 if event does not match starget + **/ +static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) +{ + if (evt->cmnd && scsi_target(evt->cmnd->device) == device) + return 1; + return 0; +} + +/** + * ibmvfc_match_lun - Match function for specified LUN + * @evt: ibmvfc event struct + * @device: device to match (sdev) + * + * Returns: + * 1 if event matches sdev / 0 if event does not match sdev + **/ +static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) +{ + if (evt->cmnd && evt->cmnd->device == device) + return 1; + return 0; +} + +/** + * ibmvfc_wait_for_ops - Wait for ops to complete + * @vhost: ibmvfc host struct + * @device: device to match (starget or sdev) + * @match: match function + * + * Returns: + * SUCCESS / FAILED + **/ +static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, + int (*match) (struct ibmvfc_event *, void *)) +{ + struct ibmvfc_event *evt; + DECLARE_COMPLETION_ONSTACK(comp); + int wait; + unsigned long flags; + signed long timeout = init_timeout * HZ; + + ENTER; + do { + wait = 0; + spin_lock_irqsave(vhost->host->host_lock, flags); + list_for_each_entry(evt, &vhost->sent, queue) { + if (match(evt, device)) { + evt->eh_comp = ∁ + wait++; + } + } + spin_unlock_irqrestore(vhost->host->host_lock, flags); + + if (wait) { + timeout = wait_for_completion_timeout(&comp, timeout); + + if (!timeout) { + wait = 0; + spin_lock_irqsave(vhost->host->host_lock, flags); + list_for_each_entry(evt, &vhost->sent, queue) { + if (match(evt, device)) { + evt->eh_comp = NULL; + wait++; + } + } + spin_unlock_irqrestore(vhost->host->host_lock, flags); + if (wait) + dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); + LEAVE; + return wait ? FAILED : SUCCESS; + } + } + } while (wait); + + LEAVE; + return SUCCESS; +} + +/** * ibmvfc_eh_abort_handler - Abort a command * @cmd: scsi command to abort * @@ -1867,29 +1963,21 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) **/ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) { - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); - struct ibmvfc_event *evt, *pos; + struct scsi_device *sdev = cmd->device; + struct ibmvfc_host *vhost = shost_priv(sdev->host); int cancel_rc, abort_rc; - unsigned long flags; + int rc = FAILED; ENTER; ibmvfc_wait_while_resetting(vhost); - cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET); - abort_rc = ibmvfc_abort_task_set(cmd->device); + cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); + abort_rc = ibmvfc_abort_task_set(sdev); - if (!cancel_rc && !abort_rc) { - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { - if (evt->cmnd && evt->cmnd->device == cmd->device) - ibmvfc_fail_request(evt, DID_ABORT); - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - LEAVE; - return SUCCESS; - } + if (!cancel_rc && !abort_rc) + rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); LEAVE; - return FAILED; + return rc; } /** @@ -1901,29 +1989,21 @@ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) **/ static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) { - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); - struct ibmvfc_event *evt, *pos; + struct scsi_device *sdev = cmd->device; + struct ibmvfc_host *vhost = shost_priv(sdev->host); int cancel_rc, reset_rc; - unsigned long flags; + int rc = FAILED; ENTER; ibmvfc_wait_while_resetting(vhost); - cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET); - reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN"); + cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); + reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); - if (!cancel_rc && !reset_rc) { - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { - if (evt->cmnd && evt->cmnd->device == cmd->device) - ibmvfc_fail_request(evt, DID_ABORT); - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - LEAVE; - return SUCCESS; - } + if (!cancel_rc && !reset_rc) + rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); LEAVE; - return FAILED; + return rc; } /** @@ -1959,31 +2039,23 @@ static void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data) **/ static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) { - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); - struct scsi_target *starget = scsi_target(cmd->device); - struct ibmvfc_event *evt, *pos; + struct scsi_device *sdev = cmd->device; + struct ibmvfc_host *vhost = shost_priv(sdev->host); + struct scsi_target *starget = scsi_target(sdev); int reset_rc; + int rc = FAILED; unsigned long cancel_rc = 0; - unsigned long flags; ENTER; ibmvfc_wait_while_resetting(vhost); starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); - reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target"); + reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); - if (!cancel_rc && !reset_rc) { - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { - if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) - ibmvfc_fail_request(evt, DID_ABORT); - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - LEAVE; - return SUCCESS; - } + if (!cancel_rc && !reset_rc) + rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); LEAVE; - return FAILED; + return rc; } /** @@ -2013,23 +2085,18 @@ static void ibmvfc_terminate_rport_io(struct fc_rport *rport) struct scsi_target *starget = to_scsi_target(&rport->dev); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct ibmvfc_host *vhost = shost_priv(shost); - struct ibmvfc_event *evt, *pos; unsigned long cancel_rc = 0; unsigned long abort_rc = 0; - unsigned long flags; + int rc = FAILED; ENTER; starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); - if (!cancel_rc && !abort_rc) { - spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { - if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) - ibmvfc_fail_request(evt, DID_ABORT); - } - spin_unlock_irqrestore(shost->host_lock, flags); - } else + if (!cancel_rc && !abort_rc) + rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); + + if (rc == FAILED) ibmvfc_issue_fc_host_lip(shost); LEAVE; } @@ -2089,15 +2156,17 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, case IBMVFC_AE_LINK_UP: case IBMVFC_AE_RESUME: vhost->events_to_log |= IBMVFC_AE_LINKUP; - ibmvfc_init_host(vhost, 1); + vhost->delay_init = 1; + __ibmvfc_reset_host(vhost); break; case IBMVFC_AE_SCN_FABRIC: + case IBMVFC_AE_SCN_DOMAIN: vhost->events_to_log |= IBMVFC_AE_RSCN; - ibmvfc_init_host(vhost, 1); + vhost->delay_init = 1; + __ibmvfc_reset_host(vhost); break; case IBMVFC_AE_SCN_NPORT: case IBMVFC_AE_SCN_GROUP: - case IBMVFC_AE_SCN_DOMAIN: vhost->events_to_log |= IBMVFC_AE_RSCN; case IBMVFC_AE_ELS_LOGO: case IBMVFC_AE_ELS_PRLO: @@ -2263,6 +2332,28 @@ static int ibmvfc_slave_alloc(struct scsi_device *sdev) } /** + * ibmvfc_target_alloc - Setup the target's task set value + * @starget: struct scsi_target + * + * Set the target's task set value so that error handling works as + * expected. + * + * Returns: + * 0 on success / -ENXIO if device does not exist + **/ +static int ibmvfc_target_alloc(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ibmvfc_host *vhost = shost_priv(shost); + unsigned long flags = 0; + + spin_lock_irqsave(shost->host_lock, flags); + starget->hostdata = (void *)(unsigned long)vhost->task_set++; + spin_unlock_irqrestore(shost->host_lock, flags); + return 0; +} + +/** * ibmvfc_slave_configure - Configure the device * @sdev: struct scsi_device device to configure * @@ -2541,6 +2632,7 @@ static struct scsi_host_template driver_template = { .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, .slave_alloc = ibmvfc_slave_alloc, .slave_configure = ibmvfc_slave_configure, + .target_alloc = ibmvfc_target_alloc, .scan_finished = ibmvfc_scan_finished, .change_queue_depth = ibmvfc_change_queue_depth, .change_queue_type = ibmvfc_change_queue_type, @@ -2637,7 +2729,7 @@ static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { vio_disable_interrupts(vdev); ibmvfc_handle_async(async, vhost); - crq->valid = 0; + async->valid = 0; } else done = 1; } @@ -2669,7 +2761,7 @@ static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, void (*job_step) (struct ibmvfc_target *)) { - if (++tgt->init_retries > IBMVFC_MAX_INIT_RETRIES) { + if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); wake_up(&tgt->vhost->work_wait_q); } else @@ -2708,6 +2800,8 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) rsp->status, rsp->error, status); if (ibmvfc_retry_cmd(rsp->status, rsp->error)) ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); + else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); break; }; @@ -2802,6 +2896,8 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) if (ibmvfc_retry_cmd(rsp->status, rsp->error)) ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); + else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); break; }; @@ -3093,6 +3189,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); + else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); break; }; @@ -3423,6 +3521,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) case IBMVFC_HOST_ACTION_ALLOC_TGTS: case IBMVFC_HOST_ACTION_TGT_ADD: case IBMVFC_HOST_ACTION_TGT_DEL: + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_QUERY: default: break; @@ -3519,7 +3618,13 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) break; case IBMVFC_HOST_ACTION_INIT: BUG_ON(vhost->state != IBMVFC_INITIALIZING); - vhost->job_step(vhost); + if (vhost->delay_init) { + vhost->delay_init = 0; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + ssleep(15); + return; + } else + vhost->job_step(vhost); break; case IBMVFC_HOST_ACTION_QUERY: list_for_each_entry(tgt, &vhost->targets, queue) @@ -3538,6 +3643,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); break; case IBMVFC_HOST_ACTION_TGT_DEL: + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: list_for_each_entry(tgt, &vhost->targets, queue) { if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { tgt_dbg(tgt, "Deleting rport\n"); @@ -3553,8 +3659,17 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) } if (vhost->state == IBMVFC_INITIALIZING) { - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); - vhost->job_step = ibmvfc_discover_targets; + if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { + ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); + vhost->init_retries = 0; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + scsi_unblock_requests(vhost->host); + return; + } else { + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); + vhost->job_step = ibmvfc_discover_targets; + } } else { ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); spin_unlock_irqrestore(vhost->host->host_lock, flags); @@ -3577,14 +3692,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) } } - if (!ibmvfc_dev_init_to_do(vhost)) { - ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); - vhost->init_retries = 0; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - scsi_unblock_requests(vhost->host); - return; - } + if (!ibmvfc_dev_init_to_do(vhost)) + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); break; case IBMVFC_HOST_ACTION_TGT_ADD: list_for_each_entry(tgt, &vhost->targets, queue) { @@ -3592,16 +3701,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) spin_unlock_irqrestore(vhost->host->host_lock, flags); ibmvfc_tgt_add_rport(tgt); return; - } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { - tgt_dbg(tgt, "Deleting rport\n"); - rport = tgt->rport; - tgt->rport = NULL; - list_del(&tgt->queue); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - if (rport) - fc_remote_port_delete(rport); - kref_put(&tgt->kref, ibmvfc_release_tgt); - return; } } diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index fb3177ab669..babdf3db59d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -29,11 +29,11 @@ #include "viosrp.h" #define IBMVFC_NAME "ibmvfc" -#define IBMVFC_DRIVER_VERSION "1.0.2" -#define IBMVFC_DRIVER_DATE "(August 14, 2008)" +#define IBMVFC_DRIVER_VERSION "1.0.4" +#define IBMVFC_DRIVER_DATE "(November 14, 2008)" #define IBMVFC_DEFAULT_TIMEOUT 15 -#define IBMVFC_INIT_TIMEOUT 30 +#define IBMVFC_INIT_TIMEOUT 120 #define IBMVFC_MAX_REQUESTS_DEFAULT 100 #define IBMVFC_DEBUG 0 @@ -43,7 +43,8 @@ #define IBMVFC_MAX_DISC_THREADS 4 #define IBMVFC_TGT_MEMPOOL_SZ 64 #define IBMVFC_MAX_CMDS_PER_LUN 64 -#define IBMVFC_MAX_INIT_RETRIES 3 +#define IBMVFC_MAX_HOST_INIT_RETRIES 6 +#define IBMVFC_MAX_TGT_INIT_RETRIES 3 #define IBMVFC_DEV_LOSS_TMO (5 * 60) #define IBMVFC_DEFAULT_LOG_LEVEL 2 #define IBMVFC_MAX_CDB_LEN 16 @@ -109,6 +110,7 @@ enum ibmvfc_vios_errors { IBMVFC_TRANS_CANCELLED = 0x0006, IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007, IBMVFC_INSUFFICIENT_RESOURCE = 0x0008, + IBMVFC_PLOGI_REQUIRED = 0x0010, IBMVFC_COMMAND_FAILED = 0x8000, }; @@ -337,7 +339,6 @@ struct ibmvfc_tmf { #define IBMVFC_TMF_LUA_VALID 0x40 u32 cancel_key; u32 my_cancel_key; -#define IBMVFC_TMF_CANCEL_KEY 0x80000000 u32 pad; u64 reserved[2]; }__attribute__((packed, aligned (8))); @@ -524,10 +525,10 @@ enum ibmvfc_async_event { }; struct ibmvfc_crq { - u8 valid; - u8 format; + volatile u8 valid; + volatile u8 format; u8 reserved[6]; - u64 ioba; + volatile u64 ioba; }__attribute__((packed, aligned (8))); struct ibmvfc_crq_queue { @@ -537,13 +538,13 @@ struct ibmvfc_crq_queue { }; struct ibmvfc_async_crq { - u8 valid; + volatile u8 valid; u8 pad[3]; u32 pad2; - u64 event; - u64 scsi_id; - u64 wwpn; - u64 node_name; + volatile u64 event; + volatile u64 scsi_id; + volatile u64 wwpn; + volatile u64 node_name; u64 reserved; }__attribute__((packed, aligned (8))); @@ -606,6 +607,7 @@ struct ibmvfc_event { struct srp_direct_buf *ext_list; dma_addr_t ext_list_token; struct completion comp; + struct completion *eh_comp; struct timer_list timer; }; @@ -626,6 +628,7 @@ enum ibmvfc_host_action { IBMVFC_HOST_ACTION_TGT_DEL, IBMVFC_HOST_ACTION_ALLOC_TGTS, IBMVFC_HOST_ACTION_TGT_INIT, + IBMVFC_HOST_ACTION_TGT_DEL_FAILED, IBMVFC_HOST_ACTION_TGT_ADD, }; @@ -671,6 +674,7 @@ struct ibmvfc_host { int discovery_threads; int client_migrated; int reinit; + int delay_init; int events_to_log; #define IBMVFC_AE_LINKUP 0x0001 #define IBMVFC_AE_LINKDOWN 0x0002 @@ -700,7 +704,7 @@ struct ibmvfc_host { #define ibmvfc_log(vhost, level, ...) \ do { \ - if (level >= (vhost)->log_level) \ + if ((vhost)->log_level >= level) \ dev_err((vhost)->dev, ##__VA_ARGS__); \ } while (0) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 6cad1758243..868d35ea01b 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -107,7 +107,7 @@ module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(max_channel, "Largest channel value"); module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); -module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR); +module_param_named(max_requests, max_requests, int, S_IRUGO); MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter"); /* ------------------------------------------------------------ @@ -1657,7 +1657,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) vdev->dev.driver_data = NULL; - driver_template.can_queue = max_requests; + driver_template.can_queue = max_requests - 2; host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); if (!host) { dev_err(&vdev->dev, "couldn't allocate host data\n"); |