diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-11 11:51:26 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-11 11:51:26 +0200 |
| commit | ffb45b46184f54bf84d95e82df46932294b2031a (patch) | |
| tree | cc199e0ec572fb2bf65fa4eb144f0e562bb34687 /drivers/scsi | |
| parent | 5eccd39d8efa3bc8d557be50f202bbf023837eed (diff) | |
| parent | a300e35c0a4b4a38fb53742ea6e2a203c98ee523 (diff) | |
| download | linux-stable-linux-rolling-stable.tar.gz linux-stable-linux-rolling-stable.zip | |
Merge v7.2.5linux-rolling-stable
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/scsi')
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 13 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 4 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 6 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.c | 46 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_dfs.c | 4 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_edif.c | 3 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 4 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 61 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_inline.h | 13 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 39 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 28 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_nvme.c | 31 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 14 | ||||
| -rw-r--r-- | drivers/scsi/scsi_bsg.c | 47 |
15 files changed, 242 insertions, 73 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ecd365d78ae3..d83abded2039 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1973,12 +1973,23 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, { struct megasas_instance *instance; u32 mr_nvme_pg_size; + u64 max_prp_io; instance = (struct megasas_instance *)sdev->host->hostdata; mr_nvme_pg_size = max_t(u32, instance->nvme_page_size, MR_DEFAULT_NVME_PAGE_SIZE); - lim->max_hw_sectors = max_io_size / 512; + /* + * megasas_make_prp_nvme() builds the PRP list in cmd->sg_frame without + * bounding it against that buffer, and spends one entry per page of + * it on the chain pointer. Cap the transfer at what the buffer holds, + * less one page for lists that start off a page boundary. + */ + max_prp_io = (u64)((instance->max_chain_frame_sz / sizeof(u64)) - + (instance->max_chain_frame_sz / mr_nvme_pg_size) - 1) * + mr_nvme_pg_size; + + lim->max_hw_sectors = min_t(u64, max_io_size, max_prp_io) >> SECTOR_SHIFT; lim->virt_boundary_mask = mr_nvme_pg_size - 1; } diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index e93ea76b565e..54b35893261a 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -1029,8 +1029,8 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) &(pm8001_ha->irq_vector[i])); if (rc) { for (j = 0; j < i; j++) { - free_irq(pci_irq_vector(pm8001_ha->pdev, i), - &(pm8001_ha->irq_vector[i])); + free_irq(pci_irq_vector(pm8001_ha->pdev, j), + &pm8001_ha->irq_vector[j]); } pci_free_irq_vectors(pm8001_ha->pdev); break; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 6a05ce195aa0..14c3efd0e210 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -816,7 +816,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; } @@ -1660,10 +1662,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 5e910b5ca670..5b15fc28ddd7 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1562,12 +1562,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] = @@ -1580,6 +1580,13 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job) image = list->version; count = list->count; + + if (struct_size(list, version, count) > sizeof(bsg)) { + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = + EXT_STATUS_INVALID_PARAM; + goto dealloc; + } + while (count--) { memcpy(sfp, &image->field_info, sizeof(image->field_info)); rval = qla2x00_write_sfp(vha, sfp_dma, sfp, @@ -1615,10 +1622,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] = @@ -1666,10 +1673,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] = @@ -1713,10 +1720,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] = @@ -1727,6 +1734,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); @@ -1759,10 +1772,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] = @@ -1773,6 +1786,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); @@ -2395,7 +2414,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) !IS_QLA28XX(vha->hw)) return -EPERM; - dd = kmalloc_obj(*dd); + dd = kzalloc_obj(*dd); if (!dd) { ql_log(ql_log_warn, vha, 0x70db, "Failed to allocate memory for dport.\n"); @@ -3365,9 +3384,8 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) bsg_reply->result = DID_OK << 16; bsg_reply->reply_payload_rcv_len = 0; bsg_job->reply_len = sizeof(struct fc_bsg_reply); - if (!rval) - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return QLA_SUCCESS; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index a7e3ec9bba47..c6b8e6d798c6 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 | diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 43970caca7b3..cb4278b88e1d 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_edif.c b/drivers/scsi/qla2xxx/qla_edif.c index eccedb38a515..6caae48510b3 100644 --- a/drivers/scsi/qla2xxx/qla_edif.c +++ b/drivers/scsi/qla2xxx/qla_edif.c @@ -3492,6 +3492,9 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, struct scsi_cmnd *cmd = GET_CMD_SP(sp); uint32_t handle; + if (!cmd) + return; + handle = (uint32_t)LSW(sts24->handle); /* find out if this status iosb is for a scsi read */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 880cd73feaca..ed46217ce26e 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -157,8 +157,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, break; case CS_PORT_LOGGED_OUT: if (IS_FWI2_CAPABLE(ha)) { - if (le16_to_cpu(ms_pkt->loop_id.extended) == - NPH_SNS) + if (le16_to_cpu(((struct ct_entry_24xx *) + ms_pkt)->nport_handle) == NPH_SNS) lid_is_sns = true; } else { if (le16_to_cpu(ms_pkt->loop_id.extended) == diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e746c9274cde..d38bf74ea7a5 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; } @@ -3764,11 +3782,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 @@ -10026,11 +10060,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 47fbd830ff16..abf0db7f72d5 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -54,6 +54,19 @@ qla2x00_debounce_register(volatile __le16 __iomem *addr) return (first); } +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_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 33776330956c..612e00ca1ada 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -205,6 +205,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; @@ -3406,6 +3417,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, sts24); sp->qpair->cmd_completion_cnt++; @@ -3463,6 +3482,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; } @@ -3778,10 +3809,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; @@ -4548,10 +4581,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 44e310f1a370..f604aab8b161 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2262,6 +2262,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)) @@ -4203,6 +4205,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, list_for_each_entry(vp, &ha->vp_list, list) { if (rptid_entry->vp_idx == vp->vp_idx) { found = 1; + atomic_inc(&vp->vref_count); break; } } @@ -4211,7 +4214,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, 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 @@ -4220,6 +4225,10 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, set_bit(VP_IDX_ACQUIRED, &vp->vp_flags); 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); @@ -4330,10 +4339,10 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha) if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x10bd, "Failed to issue VP config IOCB (%x).\n", rval); - } else if (vpmod->comp_status != 0) { + } else if (vpmod->entry_status != 0) { ql_dbg(ql_dbg_mbx, vha, 0x10be, "Failed to complete IOCB -- error status (%x).\n", - vpmod->comp_status); + vpmod->entry_status); rval = QLA_FUNCTION_FAILED; } else if (vpmod->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_dbg(ql_dbg_mbx, vha, 0x10bf, @@ -6490,6 +6499,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)) @@ -6498,15 +6508,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)); @@ -6528,8 +6535,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_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 2531e71c39dc..b84fe71ea340 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -374,6 +374,7 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport, srb_t *sp; int rval = QLA_FUNCTION_FAILED; uint8_t cnt = 0; + unsigned long flags; if (!fcport || fcport->deleted) goto out; @@ -440,7 +441,11 @@ out: a.vp_idx = vha->vp_idx; a.nport_handle = uctx->nport_handle; a.xchg_address = uctx->exchange_address; - qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true); + 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); + } kfree(uctx); return rval; } @@ -463,8 +468,8 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, } spin_unlock_irqrestore(&priv->cmd_lock, flags); - INIT_WORK(&priv->abort_work, qla_nvme_abort_work); - 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, @@ -501,6 +506,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, priv->sp = sp; kref_init(&sp->cmd_kref); spin_lock_init(&priv->cmd_lock); + INIT_WORK(&priv->abort_work, qla_nvme_abort_work); nvme = &sp->u.iocb_cmd; priv->fd = fd; nvme->u.nvme.desc = fd; @@ -545,8 +551,8 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, } spin_unlock_irqrestore(&priv->cmd_lock, flags); - INIT_WORK(&priv->abort_work, qla_nvme_abort_work); - 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) @@ -811,6 +817,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, kref_init(&sp->cmd_kref); spin_lock_init(&priv->cmd_lock); + INIT_WORK(&priv->abort_work, qla_nvme_abort_work); sp->priv = priv; priv->sp = sp; sp->type = SRB_NVME_CMD; @@ -1127,6 +1134,10 @@ static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha, lsrjt_iocb->rx_byte_count = 0; } +/* + * Allocates from and advances the request ring, so the caller must hold + * qp->qp_lock_ptr (the response-queue caller already holds it). + */ static int qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp, struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate) @@ -1183,6 +1194,7 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item) { struct qla_nvme_unsol_ctx *uctx = item->purls_context; struct qla_nvme_lsrjt_pt_arg a; + unsigned long flags; int ret = 1; #if (IS_ENABLED(CONFIG_NVME_FC)) @@ -1195,7 +1207,14 @@ 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; - qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true); + 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); + } list_del(&uctx->elem); kfree(uctx); } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 72b1c28e4dae..d853b4006f4e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2127,7 +2127,7 @@ skip_pio: 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; @@ -2213,10 +2213,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; @@ -3933,8 +3933,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); @@ -3959,6 +3957,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); @@ -6828,8 +6828,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); @@ -6847,6 +6845,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/scsi_bsg.c b/drivers/scsi/scsi_bsg.c index e80dec53174e..5eec248a77a6 100644 --- a/drivers/scsi/scsi_bsg.c +++ b/drivers/scsi/scsi_bsg.c @@ -18,6 +18,7 @@ struct scsi_bsg_uring_cmd_pdu { struct bio *bio; /* mapped user buffer, unmap in task work */ struct request *req; /* block request, freed in task work */ u64 response_addr; /* user space response buffer address */ + u32 max_response_len; /* user response buffer size */ }; static_assert(sizeof(struct scsi_bsg_uring_cmd_pdu) <= sizeof_field(struct io_uring_cmd, pdu)); @@ -45,8 +46,8 @@ static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw) if (scsi_status_is_check_condition(scmd->result)) { driver_status = DRIVER_SENSE; if (pdu->response_addr) - sense_len_wr = min_t(u8, scmd->sense_len, - SCSI_SENSE_BUFFERSIZE); + sense_len_wr = min_t(unsigned int, pdu->max_response_len, + scmd->sense_len); } if (sense_len_wr) { @@ -76,12 +77,10 @@ static enum rq_end_io_ret scsi_bsg_uring_cmd_done(struct request *req, static int scsi_bsg_map_user_buffer(struct request *req, struct io_uring_cmd *ioucmd, - unsigned int issue_flags, gfp_t gfp_mask) + unsigned int issue_flags, gfp_t gfp_mask, + bool is_write, u64 buf_addr, + unsigned long buf_len) { - const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd); - bool is_write = cmd->dout_xfer_len > 0; - u64 buf_addr = is_write ? cmd->dout_xferp : cmd->din_xferp; - unsigned long buf_len = is_write ? cmd->dout_xfer_len : cmd->din_xfer_len; struct iov_iter iter; int ret; @@ -104,21 +103,28 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc unsigned int issue_flags, bool open_for_write) { struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd); - const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd); + const struct bsg_uring_cmd *cmd = + io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd); struct scsi_cmnd *scmd; struct request *req; blk_mq_req_flags_t blk_flags = 0; gfp_t gfp_mask = GFP_KERNEL; + u64 request = READ_ONCE(cmd->request); + u32 request_len = READ_ONCE(cmd->request_len); + u64 dout_xferp = READ_ONCE(cmd->dout_xferp); + u32 dout_xfer_len = READ_ONCE(cmd->dout_xfer_len); + u64 din_xferp = READ_ONCE(cmd->din_xferp); + u32 din_xfer_len = READ_ONCE(cmd->din_xfer_len); int ret; if (cmd->protocol != BSG_PROTOCOL_SCSI || cmd->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD) return -EINVAL; - if (!cmd->request || cmd->request_len == 0) + if (!request || request_len == 0) return -EINVAL; - if (cmd->dout_xfer_len && cmd->din_xfer_len) { + if (dout_xfer_len && din_xfer_len) { pr_warn_once("BIDI support in bsg has been removed.\n"); return -EOPNOTSUPP; } @@ -131,20 +137,20 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc gfp_mask = GFP_NOWAIT; } - req = scsi_alloc_request(q, cmd->dout_xfer_len ? + req = scsi_alloc_request(q, dout_xfer_len ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, blk_flags); if (IS_ERR(req)) return PTR_ERR(req); scmd = blk_mq_rq_to_pdu(req); - if (cmd->request_len > sizeof(scmd->cmnd)) { + if (request_len > sizeof(scmd->cmnd)) { ret = -EINVAL; goto out_free_req; } - scmd->cmd_len = cmd->request_len; + scmd->cmd_len = request_len; scmd->allowed = SG_DEFAULT_RETRIES; - if (copy_from_user(scmd->cmnd, uptr64(cmd->request), cmd->request_len)) { + if (copy_from_user(scmd->cmnd, uptr64(request), request_len)) { ret = -EFAULT; goto out_free_req; } @@ -155,11 +161,16 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc } pdu->response_addr = cmd->response; - scmd->sense_len = cmd->max_response_len ? - min(cmd->max_response_len, SCSI_SENSE_BUFFERSIZE) : SCSI_SENSE_BUFFERSIZE; + pdu->max_response_len = cmd->max_response_len; - if (cmd->dout_xfer_len || cmd->din_xfer_len) { - ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags, gfp_mask); + if (dout_xfer_len || din_xfer_len) { + bool is_write = dout_xfer_len > 0; + u64 buf_addr = is_write ? dout_xferp : din_xferp; + unsigned long buf_len = is_write ? dout_xfer_len : din_xfer_len; + + ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags, + gfp_mask, is_write, buf_addr, + buf_len); if (ret) goto out_free_req; pdu->bio = req->bio; |
