diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 9 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 39 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 20 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 4 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 239 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 206 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 309 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 7 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 27 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 141 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_version.h | 2 |
12 files changed, 936 insertions, 69 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 0f879620150..fbcb82a2f7f 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1670,7 +1670,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) qla24xx_vport_disable(fc_vport, disable); - if (ql2xmultique_tag) { + if (ha->flags.cpu_affinity_enabled) { req = ha->req_q_map[1]; goto vport_queue; } else if (ql2xmaxqueues == 1 || !ha->npiv_info) @@ -1736,6 +1736,11 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) qla24xx_deallocate_vp_id(vha); + mutex_lock(&ha->vport_lock); + ha->cur_vport_count--; + clear_bit(vha->vp_idx, ha->vp_idx_map); + mutex_unlock(&ha->vport_lock); + if (vha->timer_active) { qla2x00_vp_stop_timer(vha); DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p " @@ -1743,7 +1748,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) vha->host_no, vha->vp_idx, vha)); } - if (vha->req->id && !ql2xmultique_tag) { + if (vha->req->id && !ha->flags.cpu_affinity_enabled) { if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) qla_printk(KERN_WARNING, ha, "Queue delete failed.\n"); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 00aa48d975a..21506186179 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -189,6 +189,7 @@ struct req_que; */ typedef struct srb { struct fc_port *fcport; + uint32_t handle; struct scsi_cmnd *cmd; /* Linux SCSI command pkt */ @@ -196,6 +197,8 @@ typedef struct srb { uint32_t request_sense_length; uint8_t *request_sense_ptr; + + void *ctx; } srb_t; /* @@ -204,6 +207,28 @@ typedef struct srb { #define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ /* + * SRB extensions. + */ +struct srb_ctx { +#define SRB_LOGIN_CMD 1 +#define SRB_LOGOUT_CMD 2 + uint16_t type; + struct timer_list timer; + + void (*free)(srb_t *sp); + void (*timeout)(srb_t *sp); +}; + +struct srb_logio { + struct srb_ctx ctx; + +#define SRB_LOGIN_RETRIED BIT_0 +#define SRB_LOGIN_COND_PLOGI BIT_1 +#define SRB_LOGIN_SKIP_PRLI BIT_2 + uint16_t flags; +}; + +/* * ISP I/O Register Set structure definitions. */ struct device_reg_2xxx { @@ -1482,7 +1507,7 @@ typedef union { uint8_t domain; uint8_t area; uint8_t al_pa; -#elif __LITTLE_ENDIAN +#elif defined(__LITTLE_ENDIAN) uint8_t al_pa; uint8_t area; uint8_t domain; @@ -1565,6 +1590,7 @@ typedef struct fc_port { #define FCF_FABRIC_DEVICE BIT_0 #define FCF_LOGIN_NEEDED BIT_1 #define FCF_TAPE_PRESENT BIT_2 +#define FCF_FCP2_DEVICE BIT_3 /* No loop ID flag. */ #define FC_NO_LOOP_ID 0x1000 @@ -2093,6 +2119,10 @@ struct qla_msix_entry { enum qla_work_type { QLA_EVT_AEN, QLA_EVT_IDC_ACK, + QLA_EVT_ASYNC_LOGIN, + QLA_EVT_ASYNC_LOGIN_DONE, + QLA_EVT_ASYNC_LOGOUT, + QLA_EVT_ASYNC_LOGOUT_DONE, }; @@ -2111,6 +2141,11 @@ struct qla_work_evt { #define QLA_IDC_ACK_REGS 7 uint16_t mb[QLA_IDC_ACK_REGS]; } idc_ack; + struct { + struct fc_port *fcport; +#define QLA_LOGIO_LOGIN_RETRIED BIT_0 + u16 data[2]; + } logio; } u; }; @@ -2224,6 +2259,7 @@ struct qla_hw_data { uint32_t chip_reset_done :1; uint32_t port0 :1; uint32_t running_gold_fw :1; + uint32_t cpu_affinity_enabled :1; } flags; /* This spinlock is used to protect "io transactions", you must @@ -2350,6 +2386,7 @@ struct qla_hw_data { (ha)->flags.msix_enabled) #define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha)) #define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha)) +#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha)) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index dfde2dd865c..66a8da5d7d0 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1126,7 +1126,7 @@ struct vp_config_entry_24xx { uint16_t id; uint16_t reserved_4; uint16_t hopct; - uint8_t reserved_5; + uint8_t reserved_5[2]; }; #define VP_RPT_ID_IOCB_TYPE 0x32 /* Report ID Acquisition entry. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 65b12d82867..f3d1d1afa95 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -52,6 +52,14 @@ extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); extern void qla84xx_put_chip(struct scsi_qla_host *); +extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); +extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, + uint16_t *); + /* * Global Data in qla_os.c source file. */ @@ -76,6 +84,15 @@ extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum fc_host_event_code, u32); extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *); +extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_post_async_login_done_work(struct scsi_qla_host *, + fc_port_t *, uint16_t *); +extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *, + fc_port_t *, uint16_t *); + extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); extern void qla2x00_abort_fcport_cmds(fc_port_t *); @@ -83,6 +100,8 @@ extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *, struct qla_hw_data *); extern void qla2x00_free_host(struct scsi_qla_host *); extern void qla2x00_relogin(struct scsi_qla_host *); +extern void qla2x00_do_work(struct scsi_qla_host *); + /* * Global Functions in qla_mid.c source file. */ @@ -135,6 +154,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); +extern int qla2x00_start_sp(srb_t *); /* * Global Function Prototypes in qla_mbx.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 917534b9f22..4647015eba6 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1674,6 +1674,10 @@ int qla2x00_fdmi_register(scsi_qla_host_t *vha) { int rval; + struct qla_hw_data *ha = vha->hw; + + if (IS_QLA2100(ha) || IS_QLA2200(ha)) + return QLA_FUNCTION_FAILED; rval = qla2x00_mgmt_svr_login(vha); if (rval) 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; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 13396beae2c..c5ccac0bef7 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -350,6 +350,7 @@ qla2x00_start_scsi(srb_t *sp) /* Build command packet */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; + sp->handle = handle; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; @@ -778,6 +779,7 @@ qla24xx_start_scsi(srb_t *sp) /* Build command packet. */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; + sp->handle = handle; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; @@ -852,9 +854,211 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) struct qla_hw_data *ha = sp->fcport->vha->hw; int affinity = cmd->request->cpu; - if (ql2xmultique_tag && affinity >= 0 && + if (ha->flags.cpu_affinity_enabled && affinity >= 0 && affinity < ha->max_rsp_queues - 1) *rsp = ha->rsp_q_map[affinity + 1]; else *rsp = ha->rsp_q_map[0]; } + +/* Generic Control-SRB manipulation functions. */ + +static void * +qla2x00_alloc_iocbs(srb_t *sp) +{ + scsi_qla_host_t *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + uint32_t index, handle; + request_t *pkt; + uint16_t cnt, req_cnt; + + pkt = NULL; + req_cnt = 1; + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + handle++; + if (handle == MAX_OUTSTANDING_COMMANDS) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + if (index == MAX_OUTSTANDING_COMMANDS) + goto queuing_error; + + /* Check for room on request queue. */ + if (req->cnt < req_cnt) { + if (ha->mqenable) + cnt = RD_REG_DWORD(®->isp25mq.req_q_out); + else if (IS_FWI2_CAPABLE(ha)) + cnt = RD_REG_DWORD(®->isp24.req_q_out); + else + cnt = qla2x00_debounce_register( + ISP_REQ_Q_OUT(ha, ®->isp)); + + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + if (req->cnt < req_cnt) + goto queuing_error; + + /* Prep packet */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + req->cnt -= req_cnt; + + pkt = req->ring_ptr; + memset(pkt, 0, REQUEST_ENTRY_SIZE); + pkt->entry_count = req_cnt; + pkt->handle = handle; + sp->handle = handle; + +queuing_error: + return pkt; +} + +static void +qla2x00_start_iocbs(srb_t *sp) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + struct req_que *req = ha->req_q_map[0]; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; + + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + /* Set chip new ring index. */ + if (ha->mqenable) { + WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); + RD_REG_DWORD(&ioreg->hccr); + } else if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + } else { + WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), req->ring_index); + RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + } +} + +static void +qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ + struct srb_logio *lio = sp->ctx; + + logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); + if (lio->flags & SRB_LOGIN_COND_PLOGI) + logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); + if (lio->flags & SRB_LOGIN_SKIP_PRLI) + logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); + logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); + logio->port_id[0] = sp->fcport->d_id.b.al_pa; + logio->port_id[1] = sp->fcport->d_id.b.area; + logio->port_id[2] = sp->fcport->d_id.b.domain; + logio->vp_index = sp->fcport->vp_idx; +} + +static void +qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + struct srb_logio *lio = sp->ctx; + uint16_t opts; + + mbx->entry_type = MBX_IOCB_TYPE;; + SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); + mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); + opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0; + opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0; + if (HAS_EXTENDED_IDS(ha)) { + mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); + mbx->mb10 = cpu_to_le16(opts); + } else { + mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts); + } + mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); + mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | + sp->fcport->d_id.b.al_pa); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); +} + +static void +qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ + logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = + cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); + logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); + logio->port_id[0] = sp->fcport->d_id.b.al_pa; + logio->port_id[1] = sp->fcport->d_id.b.area; + logio->port_id[2] = sp->fcport->d_id.b.domain; + logio->vp_index = sp->fcport->vp_idx; +} + +static void +qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + + mbx->entry_type = MBX_IOCB_TYPE;; + SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); + mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); + mbx->mb1 = HAS_EXTENDED_IDS(ha) ? + cpu_to_le16(sp->fcport->loop_id): + cpu_to_le16(sp->fcport->loop_id << 8); + mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); + mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | + sp->fcport->d_id.b.al_pa); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); + /* Implicit: mbx->mbx10 = 0. */ +} + +int +qla2x00_start_sp(srb_t *sp) +{ + int rval; + struct qla_hw_data *ha = sp->fcport->vha->hw; + void *pkt; + struct srb_ctx *ctx = sp->ctx; + unsigned long flags; + + rval = QLA_FUNCTION_FAILED; + spin_lock_irqsave(&ha->hardware_lock, flags); + pkt = qla2x00_alloc_iocbs(sp); + if (!pkt) + goto done; + + rval = QLA_SUCCESS; + switch (ctx->type) { + case SRB_LOGIN_CMD: + IS_FWI2_CAPABLE(ha) ? + qla24xx_login_iocb(sp, pkt): + qla2x00_login_iocb(sp, pkt); + break; + case SRB_LOGOUT_CMD: + IS_FWI2_CAPABLE(ha) ? + qla24xx_logout_iocb(sp, pkt): + qla2x00_logout_iocb(sp, pkt); + break; + default: + break; + } + + wmb(); + qla2x00_start_iocbs(sp); +done: + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 245e7afb4c4..b20a7169aac 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -598,9 +598,54 @@ skip_rio: break; case MBA_PORT_UPDATE: /* Port database update */ - /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + /* + * Handle only global and vn-port update events + * + * Relevant inputs: + * mb[1] = N_Port handle of changed port + * OR 0xffff for global event + * mb[2] = New login state + * 7 = Port logged out + * mb[3] = LSB is vp_idx, 0xff = all vps + * + * Skip processing if: + * Event is global, vp_idx is NOT all vps, + * vp_idx does not match + * Event is not global, vp_idx does not match + */ + if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) + || (mb[1] != 0xffff)) { + if (vha->vp_idx != (mb[3] & 0xff)) + break; + } + + /* Global event -- port logout or port unavailable. */ + if (mb[1] == 0xffff && mb[2] == 0x7) { + DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n", + vha->host_no)); + DEBUG(printk(KERN_INFO + "scsi(%ld): Port unavailable %04x %04x %04x.\n", + vha->host_no, mb[1], mb[2], mb[3])); + + if (atomic_read(&vha->loop_state) != LOOP_DOWN) { + atomic_set(&vha->loop_state, LOOP_DOWN); + atomic_set(&vha->loop_down_timer, + LOOP_DOWN_TIME); + vha->device_flags |= DFLG_NO_CABLE; + qla2x00_mark_all_devices_lost(vha, 1); + } + + if (vha->vp_idx) { + atomic_set(&vha->vp_state, VP_FAILED); + fc_vport_set_state(vha->fc_vport, + FC_VPORT_FAILED); + qla2x00_mark_all_devices_lost(vha, 1); + } + + vha->flags.management_server_logged_in = 0; + ha->link_data_rate = PORT_SPEED_UNKNOWN; break; + } /* * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET @@ -640,8 +685,9 @@ skip_rio: if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags)) break; /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff)) break; + DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", vha->host_no)); DEBUG(printk(KERN_INFO @@ -874,6 +920,249 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, } } +static srb_t * +qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, + struct req_que *req, void *iocb) +{ + struct qla_hw_data *ha = vha->hw; + sts_entry_t *pkt = iocb; + srb_t *sp = NULL; + uint16_t index; + + index = LSW(pkt->handle); + if (index >= MAX_OUTSTANDING_COMMANDS) { + qla_printk(KERN_WARNING, ha, + "%s: Invalid completion handle (%x).\n", func, index); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + goto done; + } + sp = req->outstanding_cmds[index]; + if (!sp) { + qla_printk(KERN_WARNING, ha, + "%s: Invalid completion handle (%x) -- timed-out.\n", func, + index); + return sp; + } + if (sp->handle != index) { + qla_printk(KERN_WARNING, ha, + "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle, + index); + return NULL; + } + req->outstanding_cmds[index] = NULL; +done: + return sp; +} + +static void +qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + struct mbx_entry *mbx) +{ + const char func[] = "MBX-IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + fc_port_t *fcport; + srb_t *sp; + struct srb_logio *lio; + uint16_t data[2]; + + sp = qla2x00_get_sp_from_handle(vha, func, req, mbx); + if (!sp) + return; + + type = NULL; + lio = sp->ctx; + switch (lio->ctx.type) { + case SRB_LOGIN_CMD: + type = "login"; + break; + case SRB_LOGOUT_CMD: + type = "logout"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + lio->ctx.type); + return; + } + + del_timer(&lio->ctx.timer); + fcport = sp->fcport; + + data[0] = data[1] = 0; + if (mbx->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x " + "status=%x state-flag=%x status-flags=%x.\n", + fcport->vha->host_no, sp->handle, type, + mbx->entry_status, le16_to_cpu(mbx->status), + le16_to_cpu(mbx->state_flags), + le16_to_cpu(mbx->status_flags))); + DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx))); + + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + goto done_post_logio_done_work; + } + + if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n", + fcport->vha->host_no, sp->handle, type, + le16_to_cpu(mbx->mb1))); + + data[0] = MBS_COMMAND_COMPLETE; + if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1) + fcport->flags |= FCF_FCP2_DEVICE; + + goto done_post_logio_done_work; + } + + data[0] = le16_to_cpu(mbx->mb0); + switch (data[0]) { + case MBS_PORT_ID_USED: + data[1] = le16_to_cpu(mbx->mb1); + break; + case MBS_LOOP_ID_USED: + break; + default: + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + break; + } + + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x " + "mb6=%x mb7=%x.\n", + fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status), + le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), + le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), + le16_to_cpu(mbx->mb7))); + +done_post_logio_done_work: + lio->ctx.type == SRB_LOGIN_CMD ? + qla2x00_post_async_login_done_work(fcport->vha, fcport, data): + qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); + + lio->ctx.free(sp); +} + +static void +qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, + struct logio_entry_24xx *logio) +{ + const char func[] = "LOGIO-IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + fc_port_t *fcport; + srb_t *sp; + struct srb_logio *lio; + uint16_t data[2]; + uint32_t iop[2]; + + sp = qla2x00_get_sp_from_handle(vha, func, req, logio); + if (!sp) + return; + + type = NULL; + lio = sp->ctx; + switch (lio->ctx.type) { + case SRB_LOGIN_CMD: + type = "login"; + break; + case SRB_LOGOUT_CMD: + type = "logout"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + lio->ctx.type); + return; + } + + del_timer(&lio->ctx.timer); + fcport = sp->fcport; + + data[0] = data[1] = 0; + if (logio->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", + fcport->vha->host_no, sp->handle, type, + logio->entry_status)); + DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio))); + + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + goto done_post_logio_done_work; + } + + if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-%s complete - iop0=%x.\n", + fcport->vha->host_no, sp->handle, type, + le32_to_cpu(logio->io_parameter[0]))); + + data[0] = MBS_COMMAND_COMPLETE; + if (lio->ctx.type == SRB_LOGOUT_CMD) + goto done_post_logio_done_work; + + iop[0] = le32_to_cpu(logio->io_parameter[0]); + if (iop[0] & BIT_4) { + fcport->port_type = FCT_TARGET; + if (iop[0] & BIT_8) + fcport->flags |= FCF_FCP2_DEVICE; + } + if (iop[0] & BIT_5) + fcport->port_type = FCT_INITIATOR; + if (logio->io_parameter[7] || logio->io_parameter[8]) + fcport->supported_classes |= FC_COS_CLASS2; + if (logio->io_parameter[9] || logio->io_parameter[10]) + fcport->supported_classes |= FC_COS_CLASS3; + + goto done_post_logio_done_work; + } + + iop[0] = le32_to_cpu(logio->io_parameter[0]); + iop[1] = le32_to_cpu(logio->io_parameter[1]); + switch (iop[0]) { + case LSC_SCODE_PORTID_USED: + data[0] = MBS_PORT_ID_USED; + data[1] = LSW(iop[1]); + break; + case LSC_SCODE_NPORT_USED: + data[0] = MBS_LOOP_ID_USED; + break; + case LSC_SCODE_CMD_FAILED: + if ((iop[1] & 0xff) == 0x05) { + data[0] = MBS_NOT_LOGGED_IN; + break; + } + /* Fall through. */ + default: + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED: 0; + break; + } + + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n", + fcport->vha->host_no, sp->handle, type, + le16_to_cpu(logio->comp_status), + le32_to_cpu(logio->io_parameter[0]), + le32_to_cpu(logio->io_parameter[1]))); + +done_post_logio_done_work: + lio->ctx.type == SRB_LOGIN_CMD ? + qla2x00_post_async_login_done_work(fcport->vha, fcport, data): + qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); + + lio->ctx.free(sp); +} + /** * qla2x00_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -935,6 +1224,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); break; + case MBX_IOCB_TYPE: + qla2x00_mbx_iocb_entry(vha, rsp->req, + (struct mbx_entry *)pkt); default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1223,6 +1515,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); + scsi_set_resid(cp, resid); cp->result = DID_ERROR << 16; break; } @@ -1544,6 +1837,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_report_id_acquisition(vha, (struct vp_rpt_id_entry_24xx *)pkt); break; + case LOGINOUT_PORT_IOCB_TYPE: + qla24xx_logio_entry(vha, rsp->req, + (struct logio_entry_24xx *)pkt); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1723,8 +2020,10 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) vha = qla25xx_get_host(rsp); qla24xx_process_response_queue(vha, rsp); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - + if (!ha->mqenable) { + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD_RELAXED(®->hccr); + } spin_unlock_irq(&ha->hardware_lock); return IRQ_HANDLED; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index fe69f305767..b6202fe118a 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1507,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); - if (ql2xmultique_tag) + if (ha->flags.cpu_affinity_enabled) req = ha->req_q_map[0]; else req = vha->req; @@ -2324,7 +2324,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, vha = fcport->vha; ha = vha->hw; req = vha->req; - if (ql2xmultique_tag) + if (ha->flags.cpu_affinity_enabled) rsp = ha->rsp_q_map[tag + 1]; else rsp = req->rsp; @@ -2746,7 +2746,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (rptid_entry->format == 0) { DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d," " number of VPs acquired %d\n", __func__, vha->host_no, - MSB(rptid_entry->vp_count), LSB(rptid_entry->vp_count))); + MSB(le16_to_cpu(rptid_entry->vp_count)), + LSB(le16_to_cpu(rptid_entry->vp_count)))); DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__, rptid_entry->port_id[2], rptid_entry->port_id[1], rptid_entry->port_id[0])); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index cd78c501803..42b799abba5 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -42,7 +42,6 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) set_bit(vp_id, ha->vp_idx_map); ha->num_vhosts++; - ha->cur_vport_count++; vha->vp_idx = vp_id; list_add_tail(&vha->list, &ha->vp_list); mutex_unlock(&ha->vport_lock); @@ -58,7 +57,6 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) mutex_lock(&ha->vport_lock); vp_id = vha->vp_idx; ha->num_vhosts--; - ha->cur_vport_count--; clear_bit(vp_id, ha->vp_idx_map); list_del(&vha->list); mutex_unlock(&ha->vport_lock); @@ -235,7 +233,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); } - /* To exclusively reset vport, we need to log it out first.*/ + /* + * To exclusively reset vport, we need to log it out first. Note: this + * control_vp can fail if ISP reset is already issued, this is + * expected, as the vp would be already logged out due to ISP reset. + */ if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); @@ -247,18 +249,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) static int qla2x00_do_dpc_vp(scsi_qla_host_t *vha) { - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + qla2x00_do_work(vha); if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { /* VP acquired. complete port configuration */ - if (atomic_read(&base_vha->loop_state) == LOOP_READY) { - qla24xx_configure_vp(vha); - } else { - set_bit(VP_IDX_ACQUIRED, &vha->vp_flags); - set_bit(VP_DPC_NEEDED, &base_vha->dpc_flags); - } - + qla24xx_configure_vp(vha); return 0; } @@ -309,6 +304,9 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) clear_bit(VP_DPC_NEEDED, &vha->dpc_flags); + if (!(ha->current_topology & ISP_CFG_F)) + return; + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (vp->vp_idx) ret = qla2x00_do_dpc_vp(vp); @@ -413,6 +411,11 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) vha->flags.init_done = 1; + mutex_lock(&ha->vport_lock); + set_bit(vha->vp_idx, ha->vp_idx_map); + ha->cur_vport_count++; + mutex_unlock(&ha->vport_lock); + return vha; create_vhost_failed: diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f0396e79b6f..b79fca7d461 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -287,9 +287,12 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) int ques, req, ret; struct qla_hw_data *ha = vha->hw; + if (!(ha->fw_attributes & BIT_6)) { + qla_printk(KERN_INFO, ha, + "Firmware is not multi-queue capable\n"); + goto fail; + } if (ql2xmultique_tag) { - /* CPU affinity mode */ - ha->wq = create_workqueue("qla2xxx_wq"); /* create a request queue for IO */ options |= BIT_7; req = qla25xx_create_req_que(ha, options, 0, 0, -1, @@ -299,6 +302,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) "Can't create request queue\n"); goto fail; } + ha->wq = create_workqueue("qla2xxx_wq"); vha->req = ha->req_q_map[req]; options |= BIT_1; for (ques = 1; ques < ha->max_rsp_queues; ques++) { @@ -309,6 +313,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) goto fail2; } } + ha->flags.cpu_affinity_enabled = 1; + DEBUG2(qla_printk(KERN_INFO, ha, "CPU affinity mode enabled, no. of response" " queues:%d, no. of request queues:%d\n", @@ -317,8 +323,13 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) return 0; fail2: qla25xx_delete_queues(vha); + destroy_workqueue(ha->wq); + ha->wq = NULL; fail: ha->mqenable = 0; + kfree(ha->req_q_map); + kfree(ha->rsp_q_map); + ha->max_req_queues = ha->max_rsp_queues = 1; return 1; } @@ -462,6 +473,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, sp->flags = 0; CMD_SP(cmd) = (void *)sp; cmd->scsi_done = done; + sp->ctx = NULL; return sp; } @@ -556,11 +568,8 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) unsigned long wait_iter = ABORT_WAIT_ITER; int ret = QLA_SUCCESS; - while (CMD_SP(cmd)) { + while (CMD_SP(cmd) && wait_iter--) { msleep(ABORT_POLLING_PERIOD); - - if (--wait_iter) - break; } if (CMD_SP(cmd)) ret = QLA_FUNCTION_FAILED; @@ -698,6 +707,8 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport) continue; if (sp->fcport != fcport) continue; + if (sp->ctx) + continue; spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { @@ -783,7 +794,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (sp == NULL) continue; - + if (sp->ctx) + continue; if (sp->cmd != cmd) continue; @@ -848,7 +860,8 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, sp = req->outstanding_cmds[cnt]; if (!sp) continue; - + if (sp->ctx) + continue; if (vha->vp_idx != sp->fcport->vha->vp_idx) continue; match = 0; @@ -1106,8 +1119,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) struct fc_port *fcport; struct qla_hw_data *ha = vha->hw; - if (ha->flags.enable_lip_full_login && !vha->vp_idx && - !IS_QLA81XX(ha)) { + if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) { ret = qla2x00_full_login_lip(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -1120,7 +1132,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) qla2x00_wait_for_loop_ready(vha); } - if (ha->flags.enable_lip_reset && !vha->vp_idx) { + if (ha->flags.enable_lip_reset) { ret = qla2x00_lip_reset(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -1154,6 +1166,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) int que, cnt; unsigned long flags; srb_t *sp; + struct srb_ctx *ctx; struct qla_hw_data *ha = vha->hw; struct req_que *req; @@ -1166,8 +1179,14 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) sp = req->outstanding_cmds[cnt]; if (sp) { req->outstanding_cmds[cnt] = NULL; - sp->cmd->result = res; - qla2x00_sp_compl(ha, sp); + if (!sp->ctx) { + sp->cmd->result = res; + qla2x00_sp_compl(ha, sp); + } else { + ctx = sp->ctx; + del_timer_sync(&ctx->timer); + ctx->free(sp); + } } } } @@ -1193,6 +1212,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_qla_host_t *vha = shost_priv(sdev->host); struct qla_hw_data *ha = vha->hw; struct fc_rport *rport = starget_to_rport(sdev->sdev_target); + fc_port_t *fcport = *(fc_port_t **)rport->dd_data; struct req_que *req = vha->req; if (sdev->tagged_supported) @@ -1201,6 +1221,8 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_deactivate_tcq(sdev, req->max_q_depth); rport->dev_loss_tmo = ha->port_down_retry_count; + if (sdev->type == TYPE_TAPE) + fcport->flags |= FCF_TAPE_PRESENT; return 0; } @@ -1923,6 +1945,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto probe_init_failed; /* Alloc arrays of request and response ring ptrs */ +que_init: if (!qla2x00_alloc_queues(ha)) { qla_printk(KERN_WARNING, ha, "[ERROR] Failed to allocate memory for queue" @@ -1959,11 +1982,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - if (ha->mqenable) - if (qla25xx_setup_mode(base_vha)) + if (ha->mqenable) { + if (qla25xx_setup_mode(base_vha)) { qla_printk(KERN_WARNING, ha, "Can't create queues, falling back to single" " queue mode\n"); + goto que_init; + } + } if (ha->flags.running_gold_fw) goto skip_dpc; @@ -2155,17 +2181,19 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, int defer) { struct fc_rport *rport; + scsi_qla_host_t *base_vha; if (!fcport->rport) return; rport = fcport->rport; if (defer) { + base_vha = pci_get_drvdata(vha->hw->pdev); spin_lock_irq(vha->host->host_lock); fcport->drport = rport; spin_unlock_irq(vha->host->host_lock); - set_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); + set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); + qla2xxx_wake_dpc(base_vha); } else fc_remote_port_delete(rport); } @@ -2237,8 +2265,9 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) fc_port_t *fcport; list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (vha->vp_idx != fcport->vp_idx) + if (vha->vp_idx != 0 && vha->vp_idx != fcport->vp_idx) continue; + /* * No point in marking the device as lost, if the device is * already DEAD. @@ -2246,10 +2275,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) continue; if (atomic_read(&fcport->state) == FCS_ONLINE) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); - qla2x00_schedule_rport_del(vha, fcport, defer); - } else - atomic_set(&fcport->state, FCS_DEVICE_LOST); + if (defer) + qla2x00_schedule_rport_del(vha, fcport, defer); + else if (vha->vp_idx == fcport->vp_idx) + qla2x00_schedule_rport_del(vha, fcport, defer); + } + atomic_set(&fcport->state, FCS_DEVICE_LOST); } } @@ -2598,7 +2629,31 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) return qla2x00_post_work(vha, e); } -static void +#define qla2x00_post_async_work(name, type) \ +int qla2x00_post_async_##name##_work( \ + struct scsi_qla_host *vha, \ + fc_port_t *fcport, uint16_t *data) \ +{ \ + struct qla_work_evt *e; \ + \ + e = qla2x00_alloc_work(vha, type); \ + if (!e) \ + return QLA_FUNCTION_FAILED; \ + \ + e->u.logio.fcport = fcport; \ + if (data) { \ + e->u.logio.data[0] = data[0]; \ + e->u.logio.data[1] = data[1]; \ + } \ + return qla2x00_post_work(vha, e); \ +} + +qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); +qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE); +qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); +qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); + +void qla2x00_do_work(struct scsi_qla_host *vha) { struct qla_work_evt *e, *tmp; @@ -2620,6 +2675,21 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_IDC_ACK: qla81xx_idc_ack(vha, e->u.idc_ack.mb); break; + case QLA_EVT_ASYNC_LOGIN: + qla2x00_async_login(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_LOGIN_DONE: + qla2x00_async_login_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_LOGOUT: + qla2x00_async_logout(vha, e->u.logio.fcport); + break; + case QLA_EVT_ASYNC_LOGOUT_DONE: + qla2x00_async_logout_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -2635,6 +2705,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) int status; uint16_t next_loopid = 0; struct qla_hw_data *ha = vha->hw; + uint16_t data[2]; list_for_each_entry(fcport, &vha->vp_fcports, list) { /* @@ -2644,6 +2715,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) if (atomic_read(&fcport->state) != FCS_ONLINE && fcport->login_retry) { + fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_TAPE_PRESENT) ha->isp_ops->fabric_logout(vha, @@ -2652,13 +2724,22 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->d_id.b.area, fcport->d_id.b.al_pa); - status = qla2x00_fabric_login(vha, fcport, - &next_loopid); + if (IS_ALOGIO_CAPABLE(ha)) { + data[0] = 0; + data[1] = QLA_LOGIO_LOGIN_RETRIED; + status = qla2x00_post_async_login_work( + vha, fcport, data); + if (status == QLA_SUCCESS) + continue; + /* Attempt a retry. */ + status = 1; + } else + status = qla2x00_fabric_login(vha, + fcport, &next_loopid); } else status = qla2x00_local_device_login(vha, fcport); - fcport->login_retry--; if (status == QLA_SUCCESS) { fcport->old_loop_id = fcport->loop_id; @@ -2831,6 +2912,9 @@ qla2x00_do_dpc(void *data) */ ha->dpc_active = 0; + /* Cleanup any residual CTX SRBs. */ + qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); + return 0; } @@ -2971,6 +3055,8 @@ qla2x00_timer(scsi_qla_host_t *vha) sp = req->outstanding_cmds[index]; if (!sp) continue; + if (sp->ctx) + continue; sfcp = sp->fcport; if (!(sfcp->flags & FCF_TAPE_PRESENT)) continue; @@ -2987,8 +3073,7 @@ qla2x00_timer(scsi_qla_host_t *vha) /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - if (!(vha->device_flags & DFLG_NO_CABLE) && - !vha->vp_idx) { + if (!(vha->device_flags & DFLG_NO_CABLE)) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", vha->host_no)); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 84369705a9a..ac107a2c34a 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.01-k4" +#define QLA2XXX_VERSION "8.03.01-k6" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 |