summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_init.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c239
1 files changed, 224 insertions, 15 deletions
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index f2ce8e3cc91..9e3eaac2559 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -40,6 +40,210 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
static int qla25xx_init_queues(struct qla_hw_data *);
+/* SRB Extensions ---------------------------------------------------------- */
+
+static void
+qla2x00_ctx_sp_timeout(unsigned long __data)
+{
+ srb_t *sp = (srb_t *)__data;
+ struct srb_ctx *ctx;
+ fc_port_t *fcport = sp->fcport;
+ struct qla_hw_data *ha = fcport->vha->hw;
+ struct req_que *req;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ req = ha->req_q_map[0];
+ req->outstanding_cmds[sp->handle] = NULL;
+ ctx = sp->ctx;
+ ctx->timeout(sp);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ ctx->free(sp);
+}
+
+static void
+qla2x00_ctx_sp_free(srb_t *sp)
+{
+ struct srb_ctx *ctx = sp->ctx;
+
+ kfree(ctx);
+ mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
+}
+
+inline srb_t *
+qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
+ unsigned long tmo)
+{
+ srb_t *sp;
+ struct qla_hw_data *ha = vha->hw;
+ struct srb_ctx *ctx;
+
+ sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
+ if (!sp)
+ goto done;
+ ctx = kzalloc(size, GFP_KERNEL);
+ if (!ctx) {
+ mempool_free(sp, ha->srb_mempool);
+ goto done;
+ }
+
+ memset(sp, 0, sizeof(*sp));
+ sp->fcport = fcport;
+ sp->ctx = ctx;
+ ctx->free = qla2x00_ctx_sp_free;
+
+ init_timer(&ctx->timer);
+ if (!tmo)
+ goto done;
+ ctx->timer.expires = jiffies + tmo * HZ;
+ ctx->timer.data = (unsigned long)sp;
+ ctx->timer.function = qla2x00_ctx_sp_timeout;
+ add_timer(&ctx->timer);
+done:
+ return sp;
+}
+
+/* Asynchronous Login/Logout Routines -------------------------------------- */
+
+#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
+
+static void
+qla2x00_async_logio_timeout(srb_t *sp)
+{
+ fc_port_t *fcport = sp->fcport;
+ struct srb_logio *lio = sp->ctx;
+
+ DEBUG2(printk(KERN_WARNING
+ "scsi(%ld:%x): Async-%s timeout.\n",
+ fcport->vha->host_no, sp->handle,
+ lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout"));
+
+ if (lio->ctx.type == SRB_LOGIN_CMD)
+ qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
+}
+
+int
+qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
+ uint16_t *data)
+{
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp;
+ struct srb_logio *lio;
+ int rval;
+
+ rval = QLA_FUNCTION_FAILED;
+ sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
+ ELS_TMO_2_RATOV(ha) + 2);
+ if (!sp)
+ goto done;
+
+ lio = sp->ctx;
+ lio->ctx.type = SRB_LOGIN_CMD;
+ lio->ctx.timeout = qla2x00_async_logio_timeout;
+ lio->flags |= SRB_LOGIN_COND_PLOGI;
+ if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
+ lio->flags |= SRB_LOGIN_RETRIED;
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ DEBUG2(printk(KERN_DEBUG
+ "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
+ "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
+ fcport->login_retry));
+ return rval;
+
+done_free_sp:
+ del_timer_sync(&lio->ctx.timer);
+ lio->ctx.free(sp);
+done:
+ return rval;
+}
+
+int
+qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
+{
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp;
+ struct srb_logio *lio;
+ int rval;
+
+ rval = QLA_FUNCTION_FAILED;
+ sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
+ ELS_TMO_2_RATOV(ha) + 2);
+ if (!sp)
+ goto done;
+
+ lio = sp->ctx;
+ lio->ctx.type = SRB_LOGOUT_CMD;
+ lio->ctx.timeout = qla2x00_async_logio_timeout;
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ DEBUG2(printk(KERN_DEBUG
+ "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
+ fcport->vha->host_no, sp->handle, fcport->loop_id,
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
+ return rval;
+
+done_free_sp:
+ del_timer_sync(&lio->ctx.timer);
+ lio->ctx.free(sp);
+done:
+ return rval;
+}
+
+int
+qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+ uint16_t *data)
+{
+ int rval;
+ uint8_t opts = 0;
+
+ switch (data[0]) {
+ case MBS_COMMAND_COMPLETE:
+ if (fcport->flags & FCF_TAPE_PRESENT)
+ opts |= BIT_1;
+ rval = qla2x00_get_port_database(vha, fcport, opts);
+ if (rval != QLA_SUCCESS)
+ qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ else
+ qla2x00_update_fcport(vha, fcport);
+ break;
+ case MBS_COMMAND_ERROR:
+ if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
+ set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+ else
+ qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ break;
+ case MBS_PORT_ID_USED:
+ fcport->loop_id = data[1];
+ qla2x00_post_async_login_work(vha, fcport, NULL);
+ break;
+ case MBS_LOOP_ID_USED:
+ fcport->loop_id++;
+ rval = qla2x00_find_new_loop_id(vha, fcport);
+ if (rval != QLA_SUCCESS) {
+ qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ break;
+ }
+ qla2x00_post_async_login_work(vha, fcport, NULL);
+ break;
+ }
+ return QLA_SUCCESS;
+}
+
+int
+qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+ uint16_t *data)
+{
+ qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ return QLA_SUCCESS;
+}
+
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
@@ -987,7 +1191,6 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
ha->phy_version);
if (rval != QLA_SUCCESS)
goto failed;
-
ha->flags.npiv_supported = 0;
if (IS_QLA2XXX_MIDTYPE(ha) &&
(ha->fw_attributes & BIT_2)) {
@@ -1591,7 +1794,8 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
char *st, *en;
uint16_t index;
struct qla_hw_data *ha = vha->hw;
- int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha);
+ int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
+ !IS_QLA81XX(ha);
if (memcmp(model, BINZERO, len) != 0) {
strncpy(ha->model_number, model, len);
@@ -1978,7 +2182,7 @@ qla2x00_rport_del(void *data)
struct fc_rport *rport;
spin_lock_irq(fcport->vha->host->host_lock);
- rport = fcport->drport;
+ rport = fcport->drport ? fcport->drport: fcport->rport;
fcport->drport = NULL;
spin_unlock_irq(fcport->vha->host->host_lock);
if (rport)
@@ -2345,8 +2549,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
struct fc_rport *rport;
struct qla_hw_data *ha = vha->hw;
- if (fcport->drport)
- qla2x00_rport_del(fcport);
+ qla2x00_rport_del(fcport);
rport_ids.node_name = wwn_to_u64(fcport->node_name);
rport_ids.port_name = wwn_to_u64(fcport->port_name);
@@ -3039,6 +3242,12 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
rval = QLA_SUCCESS;
retry = 0;
+ if (IS_ALOGIO_CAPABLE(ha)) {
+ rval = qla2x00_post_async_login_work(vha, fcport, NULL);
+ if (!rval)
+ return rval;
+ }
+
rval = qla2x00_fabric_login(vha, fcport, next_loopid);
if (rval == QLA_SUCCESS) {
/* Send an ADISC to tape devices.*/
@@ -3133,7 +3342,7 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
} else {
fcport->port_type = FCT_TARGET;
if (mb[1] & BIT_1) {
- fcport->flags |= FCF_TAPE_PRESENT;
+ fcport->flags |= FCF_FCP2_DEVICE;
}
}
@@ -3244,7 +3453,7 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
struct req_que *req;
struct rsp_que *rsp;
- if (ql2xmultique_tag)
+ if (vha->hw->flags.cpu_affinity_enabled)
req = vha->hw->req_q_map[0];
else
req = vha->req;
@@ -3286,15 +3495,17 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
}
void
-qla2x00_update_fcports(scsi_qla_host_t *vha)
+qla2x00_update_fcports(scsi_qla_host_t *base_vha)
{
fc_port_t *fcport;
+ struct scsi_qla_host *tvp, *vha;
/* Go with deferred removal of rport references. */
- list_for_each_entry(fcport, &vha->vp_fcports, list)
- if (fcport && fcport->drport &&
- atomic_read(&fcport->state) != FCS_UNCONFIGURED)
- qla2x00_rport_del(fcport);
+ list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list)
+ list_for_each_entry(fcport, &vha->vp_fcports, list)
+ if (fcport && fcport->drport &&
+ atomic_read(&fcport->state) != FCS_UNCONFIGURED)
+ qla2x00_rport_del(fcport);
}
/*
@@ -3331,8 +3542,6 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha, 0);
- list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
- qla2x00_mark_all_devices_lost(vp, 0);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer,
@@ -4264,7 +4473,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha)
return -EINVAL;
rval = qla2x00_fw_ready(base_vha);
- if (ql2xmultique_tag)
+ if (ha->flags.cpu_affinity_enabled)
req = ha->req_q_map[0];
else
req = vha->req;