diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 3b24e8a5e29b..a4ca22024ede 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -815,7 +815,9 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, "Unable to allocate memory for VPD information update.\n"); return -ENOMEM; } + mutex_lock(&ha->optrom_mutex); ha->isp_ops->get_flash_version(vha, tmp_data); + mutex_unlock(&ha->optrom_mutex); vfree(tmp_data); break; } @@ -1676,10 +1678,8 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, rval = qla2x00_get_firmware_state(vha, state); mutex_unlock(&vha->hw->optrom_mutex); out: - if (rval != QLA_SUCCESS) { + if (rval != QLA_SUCCESS) memset(state, -1, sizeof(state)); - rval = qla2x00_get_firmware_state(vha, state); - } return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0], state[1], state[2], state[3], state[4], state[5]); diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index f9b693af8db1..ab559048dbb8 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -160,6 +160,12 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct bsg_job *bsg_job) goto exit_fcp_prio_cfg; } + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) { + ret = -EINVAL; + goto exit_fcp_prio_cfg; + } + /* Get the sub command */ oper = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; @@ -758,6 +764,10 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) return -EIO; } + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 3 * sizeof(uint32_t)) + return -EINVAL; + memset(&elreq, 0, sizeof(elreq)); elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev, @@ -990,6 +1000,10 @@ qla84xx_reset(struct bsg_job *bsg_job) return -EINVAL; } + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) + return -EINVAL; + flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW); @@ -1034,6 +1048,10 @@ qla84xx_updatefw(struct bsg_job *bsg_job) return -EINVAL; } + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) + return -EINVAL; + sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); if (!sg_cnt) { @@ -1511,9 +1529,15 @@ qla2x00_read_optrom(struct bsg_job *bsg_job) struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + uint32_t start; int rval = 0; + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) + return -EINVAL; + + start = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + if (ha->flags.nic_core_reset_hdlr_active) return -EBUSY; @@ -1556,9 +1580,15 @@ qla2x00_update_optrom(struct bsg_job *bsg_job) struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + uint32_t start; int rval = 0; + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) + return -EINVAL; + + start = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + mutex_lock(&ha->optrom_mutex); rval = qla2x00_optrom_setup(bsg_job, vha, start, 1); if (rval) { @@ -1973,12 +2003,12 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job) scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; + uint8_t bsg[DMA_POOL_SIZE] = {}; struct qla_image_version_list *list = (void *)bsg; struct qla_image_version *image; uint32_t count; dma_addr_t sfp_dma; - void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + void *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = @@ -2033,10 +2063,10 @@ qla2x00_read_fru_status(struct bsg_job *bsg_job) scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; + uint8_t bsg[DMA_POOL_SIZE] = {}; struct qla_status_reg *sr = (void *)bsg; dma_addr_t sfp_dma; - uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = @@ -2084,10 +2114,10 @@ qla2x00_write_fru_status(struct bsg_job *bsg_job) scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; + uint8_t bsg[DMA_POOL_SIZE] = {}; struct qla_status_reg *sr = (void *)bsg; dma_addr_t sfp_dma; - uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = @@ -2131,10 +2161,10 @@ qla2x00_write_i2c(struct bsg_job *bsg_job) scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; + uint8_t bsg[DMA_POOL_SIZE] = {}; struct qla_i2c_access *i2c = (void *)bsg; dma_addr_t sfp_dma; - uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = @@ -2145,6 +2175,12 @@ qla2x00_write_i2c(struct bsg_job *bsg_job) sg_copy_to_buffer(bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c)); + if (i2c->length > sizeof(i2c->buffer)) { + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = + EXT_STATUS_INVALID_PARAM; + goto dealloc; + } + memcpy(sfp, i2c->buffer, i2c->length); rval = qla2x00_write_sfp(vha, sfp_dma, sfp, i2c->device, i2c->offset, i2c->length, i2c->option); @@ -2177,10 +2213,10 @@ qla2x00_read_i2c(struct bsg_job *bsg_job) scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; + uint8_t bsg[DMA_POOL_SIZE] = {}; struct qla_i2c_access *i2c = (void *)bsg; dma_addr_t sfp_dma; - uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); + uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); if (!sfp) { bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = @@ -2191,6 +2227,12 @@ qla2x00_read_i2c(struct bsg_job *bsg_job) sg_copy_to_buffer(bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c)); + if (i2c->length > sizeof(i2c->buffer)) { + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = + EXT_STATUS_INVALID_PARAM; + goto dealloc; + } + rval = qla2x00_read_sfp(vha, sfp_dma, sfp, i2c->device, i2c->offset, i2c->length, i2c->option); @@ -2411,6 +2453,11 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job) struct fc_port *fcport; char *type = "FC_BSG_HST_FX_MGMT"; + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + sizeof(uint32_t) + + sizeof(struct qla_mt_iocb_rqst_fx00)) + return -EINVAL; + /* Copy the IOCB specific information */ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *) &bsg_request->rqst_data.h_vendor.vendor_cmd[1]; @@ -3332,6 +3379,13 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j { struct fc_bsg_request *bsg_request = bsg_job->request; + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + sizeof(uint32_t)) { + ql_log(ql_log_warn, vha, 0x7000, + "BSG request too small for vendor cmd.\n"); + return -EINVAL; + } + ql_dbg(ql_dbg_edif, vha, 0x911b, "%s FC_BSG_HST_VENDOR cmd[0]=0x%x\n", __func__, bsg_request->rqst_data.h_vendor.vendor_cmd[0]); @@ -3475,8 +3529,11 @@ qla24xx_bsg_request(struct bsg_job *bsg_job) } /* Disable port will bring down the chip, allow enable command */ - if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT || - bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS) + if (bsg_request->msgcode == FC_BSG_HST_VENDOR && + bsg_job->request_len >= + sizeof(struct fc_bsg_request) + sizeof(uint32_t) && + (bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT || + bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS)) goto skip_chip_chk; if (vha->hw->flags.port_isolated) { @@ -3785,6 +3842,10 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) if (!IS_QLA28XX(ha) || vha->vp_idx != 0) return -EPERM; + if (bsg_job->request_len < + sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) + return -EINVAL; + mutex_lock(&ha->optrom_mutex); rval = qla28xx_do_validate_flash_image(bsg_job, &state); if (rval) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index acb58daacf35..196cfa8f8623 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -16,7 +16,7 @@ * | | | 0x2127-0x2128 | * | Queue Command and IO tracing | 0x3074 | 0x300b | * | | | 0x3027-0x3028 | - * | | | 0x303d-0x3041 | + * | | | 0x303e-0x3041 | * | | | 0x302e,0x3033 | * | | | 0x3036,0x3038 | * | | | 0x303a | @@ -172,7 +172,7 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { /* no interrupt, timed out*/ - return rval; + return QLA_FUNCTION_TIMEOUT; } if (rval) { /* error completion status */ @@ -255,7 +255,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, __be32 *ram, if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { /* no interrupt, timed out*/ - return rval; + return QLA_FUNCTION_TIMEOUT; } if (rval) { /* error completion status */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c10414453c2d..97e2a1a9ce3f 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2645,6 +2645,8 @@ typedef struct fc_port { struct list_head list; struct scsi_qla_host *vha; struct list_head unsol_ctx_head; + /* Serializes unsol_ctx_head against ISR, DPC and NVMe transport. */ + spinlock_t unsol_ctx_lock; unsigned int conf_compl_supported:1; unsigned int deleted:2; @@ -4176,6 +4178,7 @@ struct qla_hw_data { #define SRB_MIN_REQ 128 mempool_t *srb_mempool; u8 port_name[WWN_SIZE]; + u16 mbregs[32]; volatile struct { uint32_t mbox_int :1; @@ -4246,6 +4249,8 @@ struct qla_hw_data { uint32_t eeh_flush:2; #define EEH_FLUSH_RDY 1 #define EEH_FLUSH_DONE 2 + uint32_t t262_fail:1; + uint32_t t272_fail:1; uint32_t secure_mcu:1; uint32_t valid_flt:1; } flags; diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 177d47e92e49..5d08bdbcf70a 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -510,7 +510,9 @@ qla2x00_dfs_fce_write(struct file *file, const char __user *buffer, return PTR_ERR(buf); } - enable = kstrtoul(buf, 0, 0); + rc = kstrtoul(buf, 0, &enable); + if (rc) + goto out_free; rc = count; mutex_lock(&ha->fce_mutex); diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index b29abcc7f74f..98bc4a57b59b 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1442,6 +1442,10 @@ struct vp_ctrl_entry_24xx { uint8_t reserved_5[24]; }; +/* vp_idx_map is a 128-bit (16-byte) bitmap selecting target VPs. */ +#define VP_CTRL_IDX_MAP_BITS \ + (sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8) + /* * Modify Virtual Port Configuration IOCB */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5f7bc68aab3c..2b9a9c672ec6 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -228,7 +228,7 @@ qla2x00_async_iocb_timeout(void *data) srb_t *sp = data; fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; - int rc, h; + int rc, h, found; unsigned long flags; if (fcport) { @@ -251,6 +251,7 @@ qla2x00_async_iocb_timeout(void *data) lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? QLA_LOGIO_LOGIN_RETRIED : 0; + found = 0; spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { @@ -258,11 +259,19 @@ qla2x00_async_iocb_timeout(void *data) sp) { sp->qpair->req->outstanding_cmds[h] = NULL; + found = 1; break; } } spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); - sp->done(sp, QLA_FUNCTION_TIMEOUT); + /* + * Only complete the command if this path removed it + * from outstanding_cmds. Otherwise the ISR already + * completed it and a second sp->done() would race the + * submitter's freeing of the on-stack completion. + */ + if (found) + sp->done(sp, QLA_FUNCTION_TIMEOUT); } break; case SRB_LOGOUT_CMD: @@ -275,6 +284,7 @@ qla2x00_async_iocb_timeout(void *data) default: rc = qla24xx_async_abort_cmd(sp, false); if (rc) { + found = 0; spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { @@ -282,11 +292,19 @@ qla2x00_async_iocb_timeout(void *data) sp) { sp->qpair->req->outstanding_cmds[h] = NULL; + found = 1; break; } } spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); - sp->done(sp, QLA_FUNCTION_TIMEOUT); + /* + * Only complete the command if this path removed it + * from outstanding_cmds. Otherwise the ISR already + * completed it and a second sp->done() would race the + * submitter's freeing of the on-stack completion. + */ + if (found) + sp->done(sp, QLA_FUNCTION_TIMEOUT); } break; } @@ -3275,47 +3293,37 @@ qla81xx_reset_mpi(scsi_qla_host_t *vha) return qla81xx_write_mpi_register(vha, mb); } -static int -qla_chk_risc_recovery(scsi_qla_host_t *vha) +/* save MB regs at start of day for fw dump */ +static void +qla_save_mbregs(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; __le16 __iomem *mbptr = ®->mailbox0; int i; - u16 mb[32]; - int rc = QLA_SUCCESS; + u16 *mb = ha->mbregs; - if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) - return rc; + if ((!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) || + vha->flags.init_done) + return; - /* this check is only valid after RISC reset */ - mb[0] = rd_reg_word(mbptr); - mbptr++; - if (mb[0] == 0xf) { - rc = QLA_FUNCTION_FAILED; - - for (i = 1; i < 32; i++) { - mb[i] = rd_reg_word(mbptr); - mbptr++; - } - - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[0-7] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6], mb[7]); - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[8-15] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[8], mb[9], mb[10], mb[11], mb[12], mb[13], mb[14], - mb[15]); - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[16-23] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[16], mb[17], mb[18], mb[19], mb[20], mb[21], mb[22], - mb[23]); - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[24-31] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[24], mb[25], mb[26], mb[27], mb[28], mb[29], mb[30], - mb[31]); + for (i = 0; i < 32; i++) { + mb[i] = rd_reg_word(mbptr); + mbptr++; } - return rc; + + ql_log(ql_log_info, vha, 0x1015, + "mb[0-7] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6], mb[7]); + ql_log(ql_log_info, vha, 0x1015, + "mb[8-15] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[8], mb[9], mb[10], mb[11], mb[12], mb[13], mb[14], mb[15]); + ql_log(ql_log_info, vha, 0x1015, + "mb[16-23] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[16], mb[17], mb[18], mb[19], mb[20], mb[21], mb[22], mb[23]); + ql_log(ql_log_info, vha, 0x1015, + "mb[24-31] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[24], mb[25], mb[26], mb[27], mb[28], mb[29], mb[30], mb[31]); } /** @@ -3334,7 +3342,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) uint16_t wd; static int abts_cnt; /* ISP abort retry counts */ int rval = QLA_SUCCESS; - int print = 1; spin_lock_irqsave(&ha->hardware_lock, flags); @@ -3431,9 +3438,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) barrier(); if (cnt) { mdelay(1); - if (print && qla_chk_risc_recovery(vha)) - print = 0; - wd = rd_reg_word(®->mailbox0); } else { rval = QLA_FUNCTION_TIMEOUT; @@ -3453,6 +3457,8 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); + qla_save_mbregs(vha); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x015f, "Driver in %s mode\n", IS_NOPOLLING_TYPE(ha) ? "Interrupt" : "Polling"); @@ -3764,11 +3770,27 @@ int qla2x00_alloc_fce_trace(scsi_qla_host_t *vha) void qla2x00_free_fce_trace(struct qla_hw_data *ha) { - if (!ha->fce) + void *fce; + dma_addr_t fce_dma; + unsigned long flags; + + /* + * Unpublish ha->fce under hardware_lock so a firmware dump in + * progress (which reads ha->fce under the same lock) cannot race + * with the buffer being freed. + */ + spin_lock_irqsave(&ha->hardware_lock, flags); + if (!ha->fce) { + spin_unlock_irqrestore(&ha->hardware_lock, flags); return; - dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, ha->fce_dma); + } + fce = ha->fce; + fce_dma = ha->fce_dma; ha->fce = NULL; ha->fce_dma = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + dma_free_coherent(&ha->pdev->dev, FCE_SIZE, fce, fce_dma); } static void @@ -3813,18 +3835,11 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0]; - struct qla2xxx_fw_dump *fw_dump; + struct qla2xxx_fw_dump *fw_dump, *prev_fw_dump; + void *prev_mpi_fw_dump; size_t req_entry_size = qla_req_entry_size(ha); size_t rsp_entry_size = qla_rsp_entry_size(ha); - if (ha->fw_dump) { - ql_dbg(ql_dbg_init, vha, 0x00bd, - "Firmware dump already allocated.\n"); - return; - } - - ha->fw_dumped = 0; - ha->fw_dump_cap_flags = 0; dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0; req_q_size = rsp_q_size = 0; @@ -3907,13 +3922,11 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) ha->exlogin_size; } + ql_dbg(ql_dbg_init, vha, 0x00c5, + "%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n", + __func__, dump_size, ha->fw_dump_len, ha->fw_dump_alloc_len); + if (!ha->fw_dump_len || dump_size > ha->fw_dump_alloc_len) { - - ql_dbg(ql_dbg_init, vha, 0x00c5, - "%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n", - __func__, dump_size, ha->fw_dump_len, - ha->fw_dump_alloc_len); - fw_dump = vmalloc(dump_size); if (!fw_dump) { ql_log(ql_log_warn, vha, 0x00c4, @@ -3921,9 +3934,26 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) dump_size / 1024); } else { mutex_lock(&ha->optrom_mutex); - if (ha->fw_dumped) { - memcpy(fw_dump, ha->fw_dump, ha->fw_dump_len); - vfree(ha->fw_dump); + + if (ha->fw_dumped || ha->mpi_fw_dumped) { + prev_fw_dump = ha->fw_dump; + + if (ha->fw_dumped) + memcpy(fw_dump, prev_fw_dump, + ha->fw_dump_len); + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || + IS_QLA29XX(ha)) { + prev_mpi_fw_dump = ha->mpi_fw_dump; + ha->mpi_fw_dump = (char *)fw_dump + + ha->fwdt[0].dump_size; + + if (ha->mpi_fw_dumped) + memcpy(ha->mpi_fw_dump, + prev_mpi_fw_dump, + ha->mpi_fw_dump_len); + } + vfree(prev_fw_dump); ha->fw_dump = fw_dump; ha->fw_dump_alloc_len = dump_size; ql_dbg(ql_dbg_init, vha, 0x00c5, @@ -3942,7 +3972,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) { ha->mpi_fw_dump = (char *)fw_dump + - ha->fwdt[1].dump_size; + ha->fwdt[0].dump_size; mutex_unlock(&ha->optrom_mutex); return; } @@ -4339,6 +4369,16 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = qla2x00_verify_checksum(vha, srisc_address); if (rval == QLA_SUCCESS) { + /* + * Alloc a guestimate dump buffer to capture any failure + * during early phase of driver load. + */ + if (ql2xallocfwdump && + (IS_QLA27XX(ha) || IS_QLA28XX(ha) || + IS_QLA29XX(ha)) && + !vha->flags.init_done) + qla2x00_alloc_fw_dump(vha); + /* Start firmware execution. */ ql_dbg(ql_dbg_init, vha, 0x00ca, "Starting firmware.\n"); @@ -4390,6 +4430,19 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) MIN_MULTI_ID_FABRIC)) ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; + + /* + * The VP_CTRL IOCB selects target VPs + * through the fixed vp_idx_map bitmap, + * so a vp_index beyond it can be enabled + * via VP_CONFIG but never disabled via + * VP_CTRL, leaking the VP. Cap the count + * to the bitmap capacity. + */ + if (ha->max_npiv_vports >= + VP_CTRL_IDX_MAP_BITS) + ha->max_npiv_vports = + VP_CTRL_IDX_MAP_BITS - 1; } qlt_config_nvram_with_fw_version(vha); qla2x00_get_resource_cnts(vha); @@ -4935,6 +4988,8 @@ qla2x00_init_rings(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0; + vha->hw->flags.t262_fail = 0; + vha->hw->flags.t272_fail = 0; } return (rval); @@ -5655,6 +5710,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) INIT_LIST_HEAD(&fcport->gnl_entry); INIT_LIST_HEAD(&fcport->list); INIT_LIST_HEAD(&fcport->unsol_ctx_head); + spin_lock_init(&fcport->unsol_ctx_lock); INIT_LIST_HEAD(&fcport->sess_cmd_list); spin_lock_init(&fcport->sess_cmd_lock); @@ -10671,11 +10727,28 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair) { int ret = QLA_FUNCTION_FAILED; struct qla_hw_data *ha = qpair->hw; + struct rsp_que *rsp = qpair->rsp; qpair->delete_in_progress = 1; qla_free_buf_pool(qpair); + /* + * The response-queue interrupt schedules qla_do_work(), which + * dereferences qpair->rsp->req. Release the interrupt and flush + * any pending work before the request queue is freed below so a + * late completion cannot touch the freed request queue. The + * firmware queue-delete order (request then response) is kept. + */ + if (rsp && rsp->msix && rsp->msix->have_irq) { + free_irq(rsp->msix->vector, rsp->msix->handle); + rsp->msix->have_irq = 0; + rsp->msix->in_use = 0; + rsp->msix->handle = NULL; + } + if (rsp && ha->wq) + cancel_work_sync(&qpair->q_work); + ret = qla25xx_delete_req_que(vha, qpair->req); if (ret != QLA_SUCCESS) goto fail; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 9e33bcc87b39..90da4bad8e6e 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -138,6 +138,19 @@ qla_logio_set_vp_index(struct qla_hw_data *ha, void *pkt, u16 vp_idx) ((struct logio_entry_24xx *)pkt)->vp_index = vp_idx; } +static inline u8 +qla_calc_queue_count(u16 msix_count) +{ + /* + * Request/response queues are bounded by the MSI-X vector count less + * the mailbox vector. These counters are u8, so a board advertising + * e.g. 257 vectors would truncate msix_count - 1 (256) to 0 and hand + * kzalloc_objs() a zero count (ZERO_SIZE_PTR), faulting on the first + * ha->req_q_map[0] store. Clamp into [1, QLA_MAX_QUEUES - 1]. + */ + return clamp_t(u16, msix_count - 1, 1, QLA_MAX_QUEUES - 1); +} + static inline void qla2x00_poll(struct rsp_que *rsp) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index c4595626c16b..88bae1166a24 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2530,11 +2530,13 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) */ req->cnt -= req_cnt; pkt = qla_req_ring_slot(ha, req); - memset(pkt, 0, qla_req_entry_size(ha)); if (IS_QLAFX00(ha)) { + memset_io((void __iomem __force *)pkt, 0, + qla_req_entry_size(ha)); wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt); wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle); } else { + memset(pkt, 0, qla_req_entry_size(ha)); pkt->entry_count = req_cnt; pkt->handle = handle; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 9d2d11f10a76..63b70d4abbf0 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -259,6 +259,17 @@ void __qla_consume_iocb(struct scsi_qla_host *vha, struct purex_entry_24xx *purex = *pkt; entry_count_remaining = purex->entry_count; + + /* + * The caller already advanced ring_ptr past the head IOCB, so mark + * the head processed and account for it here, then consume only the + * continuation IOCBs that follow. + */ + ((response_t *)purex)->signature = RESPONSE_PROCESSED; + /* flush signature */ + wmb(); + --entry_count_remaining; + while (entry_count_remaining > 0) { new_pkt = rsp_q->ring_ptr; *pkt = new_pkt; @@ -991,14 +1002,6 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, do { while ((total_bytes > 0) && (entry_count_remaining > 0)) { - if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { - ql_dbg(ql_dbg_async, vha, 0x5084, - "Ran out of IOCBs, partial data 0x%x\n", - buffer_copy_offset); - cpu_relax(); - continue; - } - *pkt = rsp_q->ring_ptr; data = ((sts_cont_entry_t *)*pkt)->data; data_sz = qla_sts_cont_data_size(ha); @@ -1288,14 +1291,6 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt, do { while ((total_bytes > 0) && (entry_count_remaining > 0)) { - if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { - ql_dbg(ql_dbg_async, vha, 0x5084, - "Ran out of IOCBs, partial data 0x%x\n", - buffer_copy_offset); - cpu_relax(); - continue; - } - *pkt = rsp_q->ring_ptr; data = ((sts_cont_entry_t *)*pkt)->data; data_sz = qla_sts_cont_data_size(ha); @@ -3546,6 +3541,14 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } + /* Everything below is the SCSI fast path; reject other SRB types. */ + if (sp->type != SRB_SCSI_CMD) { + ql_dbg(ql_dbg_io, vha, 0x303d, + "Unexpected SRB type %x for status IOCB, sp %p.\n", + sp->type, sp); + return; + } + /* Fast path completion. */ qla_chk_edif_rx_sa_delete_pending(vha, sp, pkt); sp->qpair->cmd_completion_cnt++; @@ -3603,6 +3606,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) { /* Sense data lies beyond any FCP RESPONSE data. */ if (IS_FWI2_CAPABLE(ha)) { + /* + * A hostile or buggy target may report an + * rsp_info_len larger than the IOCB data area. + * Clamp it so the par_sense_len subtraction cannot + * underflow and walk sense_data out of bounds. + */ + if (rsp_info_len > par_sense_len) { + ql_log(ql_log_warn, fcport->vha, 0x3107, + "Truncating bogus rsp_info_len 0x%x to 0x%x.\n", + rsp_info_len, par_sense_len); + rsp_info_len = par_sense_len; + } sense_data += rsp_info_len; par_sense_len -= rsp_info_len; } @@ -3921,10 +3936,12 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) "iocb type %xh with error status %xh, handle %xh, rspq id %d\n", pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id); - if (que >= ha->max_req_queues || !ha->req_q_map[que]) + if (que >= ha->max_req_queues) goto fatal; req = ha->req_q_map[que]; + if (!req) + goto fatal; if (pkt->entry_status & RF_BUSY) res = DID_BUS_BUSY << 16; @@ -4261,9 +4278,24 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, "SCM not active for this port\n"); break; } + if (qla_chk_cont_iocb_avail(vha, rsp, + (response_t *)pkt, rsp_in)) { + /* + * ring_ptr and ring_index were + * pre-incremented above. Reset them + * back to current. Wait for next + * interrupt with all IOCBs to arrive + * and re-process. + */ + qla_rsp_ring_rewind_to(rsp, + (response_t *)pkt, cur_ring_index); + + ql_dbg(ql_dbg_init, vha, 0x5095, + "Defer processing FPIN...\n"); + return; + } pure_item = qla27xx_copy_fpin_pkt(vha, (void **)&pkt, &rsp); - __update_rsp_in(is_shadow_hba, rsp, rsp_in); if (!pure_item) break; qla24xx_queue_purex_item(vha, pure_item, @@ -4705,10 +4737,10 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) ha->msix_count = ret; /* Recalculate queue values */ if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) { - ha->max_req_queues = ha->msix_count - 1; + ha->max_req_queues = qla_calc_queue_count(ha->msix_count); /* ATIOQ needs 1 vector. That's 1 less QPair */ - if (QLA_TGT_MODE_ENABLED()) + if (QLA_TGT_MODE_ENABLED() && ha->max_req_queues > 1) ha->max_req_queues--; ha->max_rsp_queues = ha->max_req_queues; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index ba4a4764de1f..59ec5605930b 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2276,6 +2276,8 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) if (!ha->flags.fw_started) return QLA_FUNCTION_FAILED; + memset(&mc, 0, sizeof(mc)); + mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; if (IS_FWI2_CAPABLE(vha->hw)) @@ -4266,6 +4268,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) spin_lock_irqsave(&ha->vport_slock, flags); list_for_each_entry(vp, &ha->vp_list, list) { if (vp_idx == vp->vp_idx) { + if (test_bit(VPORT_DELETE, &vp->dpc_flags)) + break; found = 1; atomic_inc(&vp->vref_count); break; @@ -4276,7 +4280,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) if (!found) return; + spin_lock_irqsave(&ha->vport_slock, flags); qla_update_host_map(vp, id); + spin_unlock_irqrestore(&ha->vport_slock, flags); /* * Cannot configure here as we are still sitting on the @@ -4286,7 +4292,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags); set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags); + spin_lock_irqsave(&ha->vport_slock, flags); atomic_dec(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); } set_bit(VP_DPC_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); @@ -6571,6 +6579,7 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; dma_addr_t dd_dma; + void *dd; if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw)) @@ -6579,15 +6588,12 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x119f, "Entered %s.\n", __func__); - dd_dma = dma_map_single(&vha->hw->pdev->dev, - dd_buf, size, DMA_FROM_DEVICE); - if (dma_mapping_error(&vha->hw->pdev->dev, dd_dma)) { - ql_log(ql_log_warn, vha, 0x1194, "Failed to map dma buffer.\n"); + dd = dma_alloc_coherent(&vha->hw->pdev->dev, size, &dd_dma, GFP_KERNEL); + if (!dd) { + ql_log(ql_log_warn, vha, 0x1194, "Failed to allocate dma buffer.\n"); return QLA_MEMORY_ALLOC_FAILED; } - memset(dd_buf, 0, size); - mcp->mb[0] = MBC_DPORT_DIAGNOSTICS; mcp->mb[1] = options; mcp->mb[2] = MSW(LSD(dd_dma)); @@ -6609,8 +6615,9 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, "Done %s.\n", __func__); } - dma_unmap_single(&vha->hw->pdev->dev, dd_dma, - size, DMA_FROM_DEVICE); + memcpy(dd_buf, dd, size); + + dma_free_coherent(&vha->hw->pdev->dev, size, dd, dd_dma); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index b7d9c1a53f3c..4ad23d206add 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -606,6 +606,10 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) rsp->msix->handle = NULL; } + /* Flush any queued response work before freeing the queue/qpair. */ + if (rsp->qpair && ha->wq) + cancel_work_sync(&rsp->qpair->q_work); + if (rsp->ring) dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) * rsp_entry_size, @@ -992,7 +996,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) * (16-byte) vp_idx_map bitmap, so vp_index must fit within it even * if firmware advertises more NPIV vports. */ - if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8) + if (vp_index > VP_CTRL_IDX_MAP_BITS) return QLA_PARAMETER_ERROR; /* ref: INIT */ diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 8dc6df6c2e1c..beccece1e7d9 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -257,7 +257,9 @@ static void qla_nvme_release_lsrsp_cmd_kref(struct kref *kref) fd_rsp = uctx->fd_rsp; + spin_lock_irqsave(&uctx->fcport->unsol_ctx_lock, flags); list_del(&uctx->elem); + spin_unlock_irqrestore(&uctx->fcport->unsol_ctx_lock, flags); fd_rsp->done(fd_rsp); kfree(uctx); @@ -441,9 +443,14 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport, a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; - spin_lock_irqsave(ha->base_qpair->qp_lock_ptr, flags); - qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true); - spin_unlock_irqrestore(ha->base_qpair->qp_lock_ptr, flags); + if (ha->flags.fw_started) { + spin_lock_irqsave(ha->base_qpair->qp_lock_ptr, flags); + qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true); + spin_unlock_irqrestore(ha->base_qpair->qp_lock_ptr, flags); + } + spin_lock_irqsave(&uctx->fcport->unsol_ctx_lock, flags); + list_del(&uctx->elem); + spin_unlock_irqrestore(&uctx->fcport->unsol_ctx_lock, flags); kfree(uctx); return rval; } @@ -466,7 +473,8 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, } spin_unlock_irqrestore(&priv->cmd_lock, flags); - schedule_work(&priv->abort_work); + if (!schedule_work(&priv->abort_work)) + kref_put(&priv->sp->cmd_kref, priv->sp->put_fn); } static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, @@ -548,7 +556,8 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, } spin_unlock_irqrestore(&priv->cmd_lock, flags); - schedule_work(&priv->abort_work); + if (!schedule_work(&priv->abort_work)) + kref_put(&priv->sp->cmd_kref, priv->sp->put_fn); } static inline int qla2x00_start_nvme_mq(srb_t *sp) @@ -1319,10 +1328,17 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item) a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; - spin_lock_irqsave(vha->hw->base_qpair->qp_lock_ptr, flags); - qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true); - spin_unlock_irqrestore(vha->hw->base_qpair->qp_lock_ptr, flags); + if (vha->hw->flags.fw_started) { + spin_lock_irqsave(vha->hw->base_qpair->qp_lock_ptr, + flags); + qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, + true); + spin_unlock_irqrestore(vha->hw->base_qpair->qp_lock_ptr, + flags); + } + spin_lock_irqsave(&uctx->fcport->unsol_ctx_lock, flags); list_del(&uctx->elem); + spin_unlock_irqrestore(&uctx->fcport->unsol_ctx_lock, flags); kfree(uctx); } } @@ -1364,6 +1380,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) struct purex_item *item; port_id_t d_id = {0}; port_id_t id = {0}; + unsigned long flags; u8 *opcode; bool xmt_reject = false; @@ -1429,7 +1446,9 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) uctx->ox_id = p->ox_id; qla_rport->uctx = uctx; INIT_LIST_HEAD(&uctx->elem); + spin_lock_irqsave(&fcport->unsol_ctx_lock, flags); list_add_tail(&uctx->elem, &fcport->unsol_ctx_head); + spin_unlock_irqrestore(&fcport->unsol_ctx_lock, flags); item->purls_context = (void *)uctx; ql_dbg(ql_dbg_unsol, vha, 0x2121, diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ad2bd8675ce9..c0efdbff5da7 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2132,7 +2132,7 @@ qla2x00_iospace_config(struct qla_hw_data *ha) ha->msix_count = msix + 1; /* Max queues are bounded by available msix vectors */ /* MB interrupt uses 1 vector */ - ha->max_req_queues = ha->msix_count - 1; + ha->max_req_queues = qla_calc_queue_count(ha->msix_count); ha->max_rsp_queues = ha->max_req_queues; /* Queue pairs is the max value minus the base queue pair */ ha->max_qpairs = ha->max_rsp_queues - 1; @@ -2224,10 +2224,10 @@ qla83xx_iospace_config(struct qla_hw_data *ha) */ if (ql2xmqsupport || ql2xnvmeenable) { /* MB interrupt uses 1 vector */ - ha->max_req_queues = ha->msix_count - 1; + ha->max_req_queues = qla_calc_queue_count(ha->msix_count); /* ATIOQ needs 1 vector. That's 1 less QPair */ - if (QLA_TGT_MODE_ENABLED()) + if (QLA_TGT_MODE_ENABLED() && ha->max_req_queues > 1) ha->max_req_queues--; ha->max_rsp_queues = ha->max_req_queues; @@ -3725,6 +3725,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (test_bit(UNLOADING, &base_vha->dpc_flags)) return -ENODEV; + /* + * FW dump can happens before sysfs nodes are created. If sysfs nodes + * are unavailable then udev script will not be able to read the fw dump. + * Notify udev to read again, now that sysfs nodes are available. + */ + if (ha->fw_dumped || ha->mpi_fw_dumped) + qla2x00_post_uevent_work(base_vha, QLA_UEVENT_CODE_FW_DUMP); + return 0; probe_failed: @@ -4044,8 +4052,6 @@ qla2x00_remove_one(struct pci_dev *pdev) qla2x00_dfs_remove(base_vha); - qla84xx_put_chip(base_vha); - /* Disable timer */ if (base_vha->timer_active) qla2x00_stop_timer(base_vha); @@ -4070,6 +4076,8 @@ qla2x00_remove_one(struct pci_dev *pdev) scsi_remove_host(base_vha->host); + qla84xx_put_chip(base_vha); + qla2x00_free_device(base_vha); qla2x00_clear_drv_active(ha); @@ -4615,28 +4623,43 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, fail_lsrjt: dma_free_coherent(&ha->pdev->dev, ha->elsrej.size, ha->elsrej.c, ha->elsrej.cdma); + ha->elsrej.c = NULL; + ha->elsrej.cdma = 0; fail_elsrej: dma_pool_destroy(ha->purex_dma_pool); + ha->purex_dma_pool = NULL; fail_flt_data: vfree(ha->flt_data); ha->flt_data = NULL; fail_flt: dma_free_coherent(&ha->pdev->dev, sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, ha->flt, ha->flt_dma); + ha->flt = NULL; + ha->flt_dma = 0; fail_flt_buffer: dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data, ha->sfp_data_dma); + ha->sfp_data = NULL; + ha->sfp_data_dma = 0; fail_sfp_data: kfree(ha->loop_id_map); + ha->loop_id_map = NULL; fail_loop_id_map: dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); + ha->async_pd = NULL; + ha->async_pd_dma = 0; fail_async_pd: dma_pool_free(ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma); + ha->sf_init_cb = NULL; + ha->sf_init_cb_dma = 0; fail_sf_init_cb: dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); + ha->ex_init_cb = NULL; + ha->ex_init_cb_dma = 0; fail_ex_init_cb: kfree(ha->npiv_info); + ha->npiv_info = NULL; fail_npiv_info: dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) * rsp_entry_size, @@ -6991,8 +7014,6 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) qla2x00_dfs_remove(base_vha); - qla84xx_put_chip(base_vha); - if (base_vha->timer_active) qla2x00_stop_timer(base_vha); @@ -7010,6 +7031,8 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) scsi_remove_host(base_vha->host); + qla84xx_put_chip(base_vha); + base_vha->flags.init_done = 0; qla25xx_delete_queues(base_vha); qla2x00_free_fcports(base_vha); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 2e5fde403442..56ef2b4c7c26 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -560,8 +560,9 @@ static void set_chunk_mpi_bits(uint16_t *options, int count, int total) * @vha: Pointer to SCSI QLogic host structure. * @opts: Options for the operation. * @buf: Buffer to read from/write to. - * @offset: Offset into the device memory. - * @length: Length of data, in bytes. + * @offset: MPI RAM address, in 32-bit words (MBC_LOAD_DUMP_MPI_RAM is + * word-addressed; not a byte offset). + * @length: Length of data, in bytes (converted internally to a word count). * @op: Operation, either QLA29XX_MPI_OP_DUMP or QLA29XX_MPI_OP_LOAD. * * Returns: diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index b0a74b036cf4..fd3984127497 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -306,6 +306,12 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, goto done; } + if (vha->hw->flags.t262_fail) { + ql_dbg(ql_dbg_misc, vha, 0xd045, + "%s: failed previously\n", __func__); + qla27xx_skip_entry(ent, buf); + goto done; + } dwords = end - start + 1; if (buf) { buf += *len; @@ -314,7 +320,12 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, ql_dbg(ql_dbg_async, vha, 0xffff, "%s: dump ram MB failed. Area %xh start %lxh end %lxh\n", __func__, area, start, end); - return INVALID_ENTRY; + + if (rc == QLA_FUNCTION_TIMEOUT) + vha->hw->flags.t262_fail = 1; + + qla27xx_skip_entry(ent, buf); + goto done; } } *len += dwords * sizeof(uint32_t); @@ -536,13 +547,12 @@ qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha, { ql_dbg(ql_dbg_misc, vha, 0xd20d, "%s: scratch [%lx]\n", __func__, *len); - qla27xx_insert32(0xaaaaaaaa, buf, len); - qla27xx_insert32(0xbbbbbbbb, buf, len); - qla27xx_insert32(0xcccccccc, buf, len); - qla27xx_insert32(0xdddddddd, buf, len); - qla27xx_insert32(*len + sizeof(uint32_t), buf, len); + + /* The data format is based on entry type t260. */ + qla27xx_insert32(offsetof(struct device_reg_24xx, mailbox0), buf, len); + qla27xx_insertbuf(vha->hw->mbregs, sizeof(vha->hw->mbregs), buf, len); if (buf) - ent->t269.scratch_size = 5 * sizeof(uint32_t); + ent->t269.scratch_size = sizeof(uint32_t) + sizeof(vha->hw->mbregs); return qla27xx_next_entry(ent); } @@ -589,17 +599,37 @@ qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha, { ulong dwords = le32_to_cpu(ent->t272.count); ulong start = le32_to_cpu(ent->t272.addr); + int rc; ql_dbg(ql_dbg_misc, vha, 0xd210, "%s: rdremram [%lx]\n", __func__, *len); + + if (vha->hw->flags.t272_fail) { + ql_dbg(ql_dbg_misc, vha, 0xd04f, + "%s: failed previously\n", __func__); + qla27xx_skip_entry(ent, buf); + goto done; + } + if (buf) { ql_dbg(ql_dbg_misc, vha, 0xd02c, "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords); buf += *len; - qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf); + rc = qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf); + if (rc != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xd01b, + "%s: dump mpi MB failed. Start %lxh dwords %lxh\n", + __func__, start, dwords); + + if (rc == QLA_FUNCTION_TIMEOUT) + vha->hw->flags.t272_fail = 1; + + qla27xx_skip_entry(ent, buf); + goto done; + } } *len += dwords * sizeof(uint32_t); - +done: return qla27xx_next_entry(ent); } diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 1c0b01d70350..ef9dc88221c9 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,7 +6,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "12.00.00.2607b1" +#define QLA2XXX_VERSION "12.00.00.2607b2" #define QLA_DRIVER_MAJOR_VER 12 #define QLA_DRIVER_MINOR_VER 00