Skip to content

Commit

Permalink
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/jejb/scsi

Pull SCSI fixes from James Bottomley:
 "Thirteen fixes, seven of which are for IBM fibre channel and three
  additional for fairly serious bugs in drivers (qla2xxx, mpt3sas,
  aacraid).

  Of the three core fixes, the most significant is probably the missed
  run queue causing an indefinite hang. The others are fixing a
  potential use after free on device close and silencing an incorrect
  warning"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: ibmvfc: Clean up transport events
  scsi: ibmvfc: Byte swap status and error codes when logging
  scsi: ibmvfc: Add failed PRLI to cmd_status lookup array
  scsi: ibmvfc: Remove "failed" from logged errors
  scsi: zfcp: reduce flood of fcrscn1 trace records on multi-element RSCN
  scsi: zfcp: fix scsi_eh host reset with port_forced ERP for non-NPIV FCP devices
  scsi: zfcp: fix rport unblock if deleted SCSI devices on Scsi_Host
  scsi: sd: Quiesce warning if device does not report optimal I/O size
  scsi: sd: Fix a race between closing an sd device and sd I/O
  scsi: core: Run queue when state is set to running after being blocked
  scsi: qla4xxx: fix a potential NULL pointer dereference
  scsi: aacraid: Insure we don't access PCIe space during AER/EEH
  scsi: mpt3sas: Fix kernel panic during expander reset
  • Loading branch information
torvalds committed Mar 29, 2019
2 parents 4ad5283 + d6e2635 commit 3467b90
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 31 deletions.
17 changes: 17 additions & 0 deletions drivers/s390/scsi/zfcp_erp.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,20 @@ static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
add_timer(&erp_action->timer);
}

void zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter,
int clear, char *dbftag)
{
unsigned long flags;
struct zfcp_port *port;

write_lock_irqsave(&adapter->erp_lock, flags);
read_lock(&adapter->port_list_lock);
list_for_each_entry(port, &adapter->port_list, list)
_zfcp_erp_port_forced_reopen(port, clear, dbftag);
read_unlock(&adapter->port_list_lock);
write_unlock_irqrestore(&adapter->erp_lock, flags);
}

static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
int clear, char *dbftag)
{
Expand Down Expand Up @@ -1341,6 +1355,9 @@ static void zfcp_erp_try_rport_unblock(struct zfcp_port *port)
struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
int lun_status;

if (sdev->sdev_state == SDEV_DEL ||
sdev->sdev_state == SDEV_CANCEL)
continue;
if (zsdev->port != port)
continue;
/* LUN under port of interest */
Expand Down
2 changes: 2 additions & 0 deletions drivers/s390/scsi/zfcp_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ extern void zfcp_erp_port_reopen(struct zfcp_port *port, int clear,
char *dbftag);
extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, char *);
extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, char *);
extern void zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter,
int clear, char *dbftag);
extern void zfcp_erp_set_lun_status(struct scsi_device *, u32);
extern void zfcp_erp_clear_lun_status(struct scsi_device *, u32);
extern void zfcp_erp_lun_reopen(struct scsi_device *, int, char *);
Expand Down
21 changes: 17 additions & 4 deletions drivers/s390/scsi/zfcp_fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,17 +239,14 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
list_for_each_entry(port, &adapter->port_list, list) {
if ((port->d_id & range) == (ntoh24(page->rscn_fid) & range))
zfcp_fc_test_link(port);
if (!port->d_id)
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
"fcrscn1");
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
}

static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
{
struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data;
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fc_els_rscn *head;
struct fc_els_rscn_page *page;
u16 i;
Expand All @@ -263,6 +260,22 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
no_entries = be16_to_cpu(head->rscn_plen) /
sizeof(struct fc_els_rscn_page);

if (no_entries > 1) {
/* handle failed ports */
unsigned long flags;
struct zfcp_port *port;

read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list) {
if (port->d_id)
continue;
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
"fcrscn1");
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
}

for (i = 1; i < no_entries; i++) {
/* skip head and start with 1st element */
page++;
Expand Down
4 changes: 4 additions & 0 deletions drivers/s390/scsi/zfcp_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,10 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
int ret = SUCCESS, fc_ret;

if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) {
zfcp_erp_port_forced_reopen_all(adapter, 0, "schrh_p");
zfcp_erp_wait(adapter);
}
zfcp_erp_adapter_reopen(adapter, 0, "schrh_1");
zfcp_erp_wait(adapter);
fc_ret = fc_block_scsi_eh(scpnt);
Expand Down
7 changes: 6 additions & 1 deletion drivers/scsi/aacraid/aacraid.h
Original file line number Diff line number Diff line change
Expand Up @@ -2640,9 +2640,14 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
return capacity;
}

static inline int aac_pci_offline(struct aac_dev *dev)
{
return pci_channel_offline(dev->pdev) || dev->handle_pci_error;
}

static inline int aac_adapter_check_health(struct aac_dev *dev)
{
if (unlikely(pci_channel_offline(dev->pdev)))
if (unlikely(aac_pci_offline(dev)))
return -1;

return (dev)->a_ops.adapter_check_health(dev);
Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/aacraid/commsup.c
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
return -ETIMEDOUT;
}

if (unlikely(pci_channel_offline(dev->pdev)))
if (unlikely(aac_pci_offline(dev)))
return -EFAULT;

if ((blink = aac_adapter_check_health(dev)) > 0) {
Expand Down Expand Up @@ -772,7 +772,7 @@ int aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback,

spin_unlock_irqrestore(&fibptr->event_lock, flags);

if (unlikely(pci_channel_offline(dev->pdev)))
if (unlikely(aac_pci_offline(dev)))
return -EFAULT;

fibptr->flags |= FIB_CONTEXT_FLAG_WAIT;
Expand Down
39 changes: 22 additions & 17 deletions drivers/scsi/ibmvscsi/ibmvfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ static const struct {
{ IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" },

{ IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" },
{ IBMVFC_FC_SCSI_ERROR, IBMVFC_COMMAND_FAILED, DID_ERROR, 0, 1, "PRLI to device failed." },
};

static void ibmvfc_npiv_login(struct ibmvfc_host *);
Expand Down Expand Up @@ -1494,9 +1495,9 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
if (rsp->flags & FCP_RSP_LEN_VALID)
rsp_code = rsp->data.info.rsp_code;

scmd_printk(KERN_ERR, cmnd, "Command (%02X) failed: %s (%x:%x) "
scmd_printk(KERN_ERR, cmnd, "Command (%02X) : %s (%x:%x) "
"flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n",
cmnd->cmnd[0], err, vfc_cmd->status, vfc_cmd->error,
cmnd->cmnd[0], err, be16_to_cpu(vfc_cmd->status), be16_to_cpu(vfc_cmd->error),
rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status);
}

Expand Down Expand Up @@ -2022,7 +2023,7 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc)
sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) "
"flags: %x fcp_rsp: %x, scsi_status: %x\n", desc,
ibmvfc_get_cmd_error(be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error)),
rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code,
be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error), fc_rsp->flags, rsp_code,
fc_rsp->scsi_status);
rsp_rc = -EIO;
} else
Expand Down Expand Up @@ -2381,7 +2382,7 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) "
"flags: %x fcp_rsp: %x, scsi_status: %x\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error)),
rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code,
be16_to_cpu(rsp_iu.cmd.status), be16_to_cpu(rsp_iu.cmd.error), fc_rsp->flags, rsp_code,
fc_rsp->scsi_status);
rsp_rc = -EIO;
} else
Expand Down Expand Up @@ -2755,16 +2756,18 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
if (crq->format == IBMVFC_PARTITION_MIGRATED) {
/* We need to re-setup the interpartition connection */
dev_info(vhost->dev, "Re-enabling adapter\n");
dev_info(vhost->dev, "Partition migrated, Re-enabling adapter\n");
vhost->client_migrated = 1;
ibmvfc_purge_requests(vhost, DID_REQUEUE);
ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
} else {
dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format);
} else if (crq->format == IBMVFC_PARTNER_FAILED || crq->format == IBMVFC_PARTNER_DEREGISTER) {
dev_err(vhost->dev, "Host partner adapter deregistered or failed (rc=%d)\n", crq->format);
ibmvfc_purge_requests(vhost, DID_ERROR);
ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
} else {
dev_err(vhost->dev, "Received unknown transport event from partner (rc=%d)\n", crq->format);
}
return;
case IBMVFC_CRQ_CMD_RSP:
Expand Down Expand Up @@ -3348,7 +3351,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt)

tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
rsp->status, rsp->error, status);
be16_to_cpu(rsp->status), be16_to_cpu(rsp->error), status);
break;
}

Expand Down Expand Up @@ -3446,9 +3449,10 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);

tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)), rsp->status, rsp->error,
ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), rsp->fc_type,
ibmvfc_get_ls_explain(be16_to_cpu(rsp->fc_explain)), rsp->fc_explain, status);
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
be16_to_cpu(rsp->status), be16_to_cpu(rsp->error),
ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), be16_to_cpu(rsp->fc_type),
ibmvfc_get_ls_explain(be16_to_cpu(rsp->fc_explain)), be16_to_cpu(rsp->fc_explain), status);
break;
}

Expand Down Expand Up @@ -3619,7 +3623,7 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
fc_explain = (be32_to_cpu(mad->fc_iu.response[1]) & 0x0000ff00) >> 8;
tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error)),
mad->iu.status, mad->iu.error,
be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error),
ibmvfc_get_fc_type(fc_reason), fc_reason,
ibmvfc_get_ls_explain(fc_explain), fc_explain, status);
break;
Expand Down Expand Up @@ -3831,9 +3835,10 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)

tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
rsp->status, rsp->error, ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)),
rsp->fc_type, ibmvfc_get_gs_explain(be16_to_cpu(rsp->fc_explain)),
rsp->fc_explain, status);
be16_to_cpu(rsp->status), be16_to_cpu(rsp->error),
ibmvfc_get_fc_type(be16_to_cpu(rsp->fc_type)), be16_to_cpu(rsp->fc_type),
ibmvfc_get_gs_explain(be16_to_cpu(rsp->fc_explain)), be16_to_cpu(rsp->fc_explain),
status);
break;
}

Expand Down Expand Up @@ -3959,7 +3964,7 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
level += ibmvfc_retry_host_init(vhost);
ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
rsp->status, rsp->error);
be16_to_cpu(rsp->status), be16_to_cpu(rsp->error));
break;
case IBMVFC_MAD_DRIVER_FAILED:
break;
Expand Down Expand Up @@ -4024,7 +4029,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n",
ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)),
rsp->status, rsp->error);
be16_to_cpu(rsp->status), be16_to_cpu(rsp->error));
ibmvfc_free_event(evt);
return;
case IBMVFC_MAD_CRQ_ERROR:
Expand Down
7 changes: 6 additions & 1 deletion drivers/scsi/ibmvscsi/ibmvfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@ enum ibmvfc_crq_valid {
IBMVFC_CRQ_XPORT_EVENT = 0xFF,
};

enum ibmvfc_crq_format {
enum ibmvfc_crq_init_msg {
IBMVFC_CRQ_INIT = 0x01,
IBMVFC_CRQ_INIT_COMPLETE = 0x02,
};

enum ibmvfc_crq_xport_evts {
IBMVFC_PARTNER_FAILED = 0x01,
IBMVFC_PARTNER_DEREGISTER = 0x02,
IBMVFC_PARTITION_MIGRATED = 0x06,
};

Expand Down
6 changes: 6 additions & 0 deletions drivers/scsi/mpt3sas/mpt3sas_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -3281,12 +3281,18 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)

if (smid < ioc->hi_priority_smid) {
struct scsiio_tracker *st;
void *request;

st = _get_st_from_smid(ioc, smid);
if (!st) {
_base_recovery_check(ioc);
return;
}

/* Clear MPI request frame */
request = mpt3sas_base_get_msg_frame(ioc, smid);
memset(request, 0, ioc->request_sz);

mpt3sas_base_clear_st(ioc, st);
_base_recovery_check(ioc);
return;
Expand Down
12 changes: 12 additions & 0 deletions drivers/scsi/mpt3sas/mpt3sas_scsih.c
Original file line number Diff line number Diff line change
Expand Up @@ -1462,11 +1462,23 @@ mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
{
struct scsi_cmnd *scmd = NULL;
struct scsiio_tracker *st;
Mpi25SCSIIORequest_t *mpi_request;

if (smid > 0 &&
smid <= ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT) {
u32 unique_tag = smid - 1;

mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);

/*
* If SCSI IO request is outstanding at driver level then
* DevHandle filed must be non-zero. If DevHandle is zero
* then it means that this smid is free at driver level,
* so return NULL.
*/
if (!mpi_request->DevHandle)
return scmd;

scmd = scsi_host_find_tag(ioc->shost, unique_tag);
if (scmd) {
st = scsi_cmd_priv(scmd);
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/qla4xxx/ql4_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -3203,6 +3203,8 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
return -EINVAL;
ep = iscsi_lookup_endpoint(transport_fd);
if (!ep)
return -EINVAL;
conn = cls_conn->dd_data;
qla_conn = conn->dd_data;
qla_conn->qla_ep = ep->dd_data;
Expand Down
6 changes: 6 additions & 0 deletions drivers/scsi/scsi_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,12 @@ store_state_field(struct device *dev, struct device_attribute *attr,

mutex_lock(&sdev->state_mutex);
ret = scsi_device_set_state(sdev, state);
/*
* If the device state changes to SDEV_RUNNING, we need to run
* the queue to avoid I/O hang.
*/
if (ret == 0 && state == SDEV_RUNNING)
blk_mq_run_hw_queues(sdev->request_queue, true);
mutex_unlock(&sdev->state_mutex);

return ret == 0 ? count : -EINVAL;
Expand Down
22 changes: 16 additions & 6 deletions drivers/scsi/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1415,11 +1415,6 @@ static void sd_release(struct gendisk *disk, fmode_t mode)
scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
}

/*
* XXX and what if there are packets in flight and this close()
* XXX is followed by a "rmmod sd_mod"?
*/

scsi_disk_put(sdkp);
}

Expand Down Expand Up @@ -3076,6 +3071,9 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp,
unsigned int opt_xfer_bytes =
logical_to_bytes(sdp, sdkp->opt_xfer_blocks);

if (sdkp->opt_xfer_blocks == 0)
return false;

if (sdkp->opt_xfer_blocks > dev_max) {
sd_first_printk(KERN_WARNING, sdkp,
"Optimal transfer size %u logical blocks " \
Expand Down Expand Up @@ -3505,9 +3503,21 @@ static void scsi_disk_release(struct device *dev)
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
struct gendisk *disk = sdkp->disk;

struct request_queue *q = disk->queue;

ida_free(&sd_index_ida, sdkp->index);

/*
* Wait until all requests that are in progress have completed.
* This is necessary to avoid that e.g. scsi_end_request() crashes
* due to clearing the disk->private_data pointer. Wait from inside
* scsi_disk_release() instead of from sd_release() to avoid that
* freezing and unfreezing the request queue affects user space I/O
* in case multiple processes open a /dev/sd... node concurrently.
*/
blk_mq_freeze_queue(q);
blk_mq_unfreeze_queue(q);

disk->private_data = NULL;
put_disk(disk);
put_device(&sdkp->device->sdev_gendev);
Expand Down

0 comments on commit 3467b90

Please sign in to comment.