forked from Minki/linux
SCSI fixes on 20201030
Four driver fixes and one core fix. The core fix closes a race window where we could kick off a second asynchronous scan because the test and set of the variable preventing it isn't atomic. Signed-off-by: James E.J. Bottomley <jejb@linux.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCX5xLJCYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishQUrAP4w7L6f 2+4qDP4ixfRMDtJmKhQVgTlm013Fx+rEGX03PQEAors1xBSTDvoG0ZnP+KbIs4qW d2Q3WTRIQ4EFUs1W/nI= =cZos -----END PGP SIGNATURE----- Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "Four driver fixes and one core fix. The core fix closes a race window where we could kick off a second asynchronous scan because the test and set of the variable preventing it isn't atomic" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: hisi_sas: Stop using queue #0 always for v2 hw scsi: ibmvscsi: Fix potential race after loss of transport scsi: mptfusion: Fix null pointer dereferences in mptscsih_remove() scsi: qla2xxx: Return EBUSY on fcport deletion scsi: core: Don't start concurrent async scan on same host
This commit is contained in:
commit
67ff377bc3
@ -1176,8 +1176,10 @@ mptscsih_remove(struct pci_dev *pdev)
|
|||||||
MPT_SCSI_HOST *hd;
|
MPT_SCSI_HOST *hd;
|
||||||
int sz1;
|
int sz1;
|
||||||
|
|
||||||
if((hd = shost_priv(host)) == NULL)
|
if (host == NULL)
|
||||||
return;
|
hd = NULL;
|
||||||
|
else
|
||||||
|
hd = shost_priv(host);
|
||||||
|
|
||||||
mptscsih_shutdown(pdev);
|
mptscsih_shutdown(pdev);
|
||||||
|
|
||||||
@ -1193,14 +1195,15 @@ mptscsih_remove(struct pci_dev *pdev)
|
|||||||
"Free'd ScsiLookup (%d) memory\n",
|
"Free'd ScsiLookup (%d) memory\n",
|
||||||
ioc->name, sz1));
|
ioc->name, sz1));
|
||||||
|
|
||||||
kfree(hd->info_kbuf);
|
if (hd)
|
||||||
|
kfree(hd->info_kbuf);
|
||||||
|
|
||||||
/* NULL the Scsi_Host pointer
|
/* NULL the Scsi_Host pointer
|
||||||
*/
|
*/
|
||||||
ioc->sh = NULL;
|
ioc->sh = NULL;
|
||||||
|
|
||||||
scsi_host_put(host);
|
if (host)
|
||||||
|
scsi_host_put(host);
|
||||||
mpt_detach(pdev);
|
mpt_detach(pdev);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -445,7 +445,7 @@ static int hisi_sas_task_prep(struct sas_task *task,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scmd) {
|
if (scmd && hisi_hba->shost->nr_hw_queues) {
|
||||||
unsigned int dq_index;
|
unsigned int dq_index;
|
||||||
u32 blk_tag;
|
u32 blk_tag;
|
||||||
|
|
||||||
|
@ -806,6 +806,22 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
|
|||||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ibmvscsi_set_request_limit - Set the adapter request_limit in response to
|
||||||
|
* an adapter failure, reset, or SRP Login. Done under host lock to prevent
|
||||||
|
* race with SCSI command submission.
|
||||||
|
* @hostdata: adapter to adjust
|
||||||
|
* @limit: new request limit
|
||||||
|
*/
|
||||||
|
static void ibmvscsi_set_request_limit(struct ibmvscsi_host_data *hostdata, int limit)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||||
|
atomic_set(&hostdata->request_limit, limit);
|
||||||
|
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ibmvscsi_reset_host - Reset the connection to the server
|
* ibmvscsi_reset_host - Reset the connection to the server
|
||||||
* @hostdata: struct ibmvscsi_host_data to reset
|
* @hostdata: struct ibmvscsi_host_data to reset
|
||||||
@ -813,7 +829,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
|
|||||||
static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
|
static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
|
||||||
{
|
{
|
||||||
scsi_block_requests(hostdata->host);
|
scsi_block_requests(hostdata->host);
|
||||||
atomic_set(&hostdata->request_limit, 0);
|
ibmvscsi_set_request_limit(hostdata, 0);
|
||||||
|
|
||||||
purge_requests(hostdata, DID_ERROR);
|
purge_requests(hostdata, DID_ERROR);
|
||||||
hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
|
hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
|
||||||
@ -1146,13 +1162,13 @@ static void login_rsp(struct srp_event_struct *evt_struct)
|
|||||||
dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
|
dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
|
||||||
evt_struct->xfer_iu->srp.login_rej.reason);
|
evt_struct->xfer_iu->srp.login_rej.reason);
|
||||||
/* Login failed. */
|
/* Login failed. */
|
||||||
atomic_set(&hostdata->request_limit, -1);
|
ibmvscsi_set_request_limit(hostdata, -1);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
|
dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
|
||||||
evt_struct->xfer_iu->srp.login_rsp.opcode);
|
evt_struct->xfer_iu->srp.login_rsp.opcode);
|
||||||
/* Login failed. */
|
/* Login failed. */
|
||||||
atomic_set(&hostdata->request_limit, -1);
|
ibmvscsi_set_request_limit(hostdata, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1163,7 +1179,7 @@ static void login_rsp(struct srp_event_struct *evt_struct)
|
|||||||
* This value is set rather than added to request_limit because
|
* This value is set rather than added to request_limit because
|
||||||
* request_limit could have been set to -1 by this client.
|
* request_limit could have been set to -1 by this client.
|
||||||
*/
|
*/
|
||||||
atomic_set(&hostdata->request_limit,
|
ibmvscsi_set_request_limit(hostdata,
|
||||||
be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
|
be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
|
||||||
|
|
||||||
/* If we had any pending I/Os, kick them */
|
/* If we had any pending I/Os, kick them */
|
||||||
@ -1195,13 +1211,13 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
|
|||||||
login->req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
|
login->req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
|
||||||
SRP_BUF_FORMAT_INDIRECT);
|
SRP_BUF_FORMAT_INDIRECT);
|
||||||
|
|
||||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
|
||||||
/* Start out with a request limit of 0, since this is negotiated in
|
/* Start out with a request limit of 0, since this is negotiated in
|
||||||
* the login request we are just sending and login requests always
|
* the login request we are just sending and login requests always
|
||||||
* get sent by the driver regardless of request_limit.
|
* get sent by the driver regardless of request_limit.
|
||||||
*/
|
*/
|
||||||
atomic_set(&hostdata->request_limit, 0);
|
ibmvscsi_set_request_limit(hostdata, 0);
|
||||||
|
|
||||||
|
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||||
rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
|
rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
|
||||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||||
dev_info(hostdata->dev, "sent SRP login\n");
|
dev_info(hostdata->dev, "sent SRP login\n");
|
||||||
@ -1781,7 +1797,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
|
|||||||
return;
|
return;
|
||||||
case VIOSRP_CRQ_XPORT_EVENT: /* Hypervisor telling us the connection is closed */
|
case VIOSRP_CRQ_XPORT_EVENT: /* Hypervisor telling us the connection is closed */
|
||||||
scsi_block_requests(hostdata->host);
|
scsi_block_requests(hostdata->host);
|
||||||
atomic_set(&hostdata->request_limit, 0);
|
ibmvscsi_set_request_limit(hostdata, 0);
|
||||||
if (crq->format == 0x06) {
|
if (crq->format == 0x06) {
|
||||||
/* We need to re-setup the interpartition connection */
|
/* We need to re-setup the interpartition connection */
|
||||||
dev_info(hostdata->dev, "Re-enabling adapter!\n");
|
dev_info(hostdata->dev, "Re-enabling adapter!\n");
|
||||||
@ -2137,12 +2153,12 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
|
hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
|
||||||
|
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
atomic_set(&hostdata->request_limit, -1);
|
ibmvscsi_set_request_limit(hostdata, -1);
|
||||||
dev_err(hostdata->dev, "error after %s\n", action);
|
dev_err(hostdata->dev, "error after %s\n", action);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
|
||||||
|
|
||||||
scsi_unblock_requests(hostdata->host);
|
scsi_unblock_requests(hostdata->host);
|
||||||
}
|
}
|
||||||
@ -2226,7 +2242,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
|
|||||||
init_waitqueue_head(&hostdata->work_wait_q);
|
init_waitqueue_head(&hostdata->work_wait_q);
|
||||||
hostdata->host = host;
|
hostdata->host = host;
|
||||||
hostdata->dev = dev;
|
hostdata->dev = dev;
|
||||||
atomic_set(&hostdata->request_limit, -1);
|
ibmvscsi_set_request_limit(hostdata, -1);
|
||||||
hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
|
hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
|
||||||
|
|
||||||
if (map_persist_bufs(hostdata)) {
|
if (map_persist_bufs(hostdata)) {
|
||||||
|
@ -554,10 +554,12 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
|
|||||||
|
|
||||||
fcport = qla_rport->fcport;
|
fcport = qla_rport->fcport;
|
||||||
|
|
||||||
if (!qpair || !fcport || (qpair && !qpair->fw_started) ||
|
if (!qpair || !fcport)
|
||||||
(fcport && fcport->deleted))
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (!qpair->fw_started || fcport->deleted)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
vha = fcport->vha;
|
vha = fcport->vha;
|
||||||
|
|
||||||
if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))
|
if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))
|
||||||
|
@ -1714,15 +1714,16 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
|
|||||||
*/
|
*/
|
||||||
static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
|
static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
|
||||||
{
|
{
|
||||||
struct async_scan_data *data;
|
struct async_scan_data *data = NULL;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (strncmp(scsi_scan_type, "sync", 4) == 0)
|
if (strncmp(scsi_scan_type, "sync", 4) == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
mutex_lock(&shost->scan_mutex);
|
||||||
if (shost->async_scan) {
|
if (shost->async_scan) {
|
||||||
shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__);
|
shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__);
|
||||||
return NULL;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||||
@ -1733,7 +1734,6 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
|
|||||||
goto err;
|
goto err;
|
||||||
init_completion(&data->prev_finished);
|
init_completion(&data->prev_finished);
|
||||||
|
|
||||||
mutex_lock(&shost->scan_mutex);
|
|
||||||
spin_lock_irqsave(shost->host_lock, flags);
|
spin_lock_irqsave(shost->host_lock, flags);
|
||||||
shost->async_scan = 1;
|
shost->async_scan = 1;
|
||||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||||
@ -1748,6 +1748,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
|
|||||||
return data;
|
return data;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
mutex_unlock(&shost->scan_mutex);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user