Commit 8a929806 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi

Pull SCSI fixes from James Bottomley:
 "The core change is to detect unusually large number of VPD pages
  (caused by device manufacturers having an endiannes issue) and reject
  them rather than trying to parse a huge non-existent array.

  The remaining fixes are in drivers the most user visible of which is
  the ALUA state transition recognition (leads to intermittent I/O
  errors in some situations otherwise)"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: ufs: mcq: Fix error output and clean up ufshcd_mcq_abort()
  scsi: core: Handle devices which return an unusually large VPD page count
  scsi: mpt3sas: Add missing kerneldoc parameter descriptions
  scsi: qedf: Set qed_slowpath_params to zero before use
  scsi: qedf: Wait for stag work during unload
  scsi: qedf: Don't process stag work during unload and recovery
  scsi: sr: Fix unintentional arithmetic wraparound
  scsi: core: alua: I/O errors for ALUA state transitions
  scsi: mpi3mr: Use proper format specifier in mpi3mr_sas_port_add()
parents d91e6562 d53b681c
...@@ -217,7 +217,7 @@ current *struct* is:: ...@@ -217,7 +217,7 @@ current *struct* is::
int (*media_changed)(struct cdrom_device_info *, int); int (*media_changed)(struct cdrom_device_info *, int);
int (*tray_move)(struct cdrom_device_info *, int); int (*tray_move)(struct cdrom_device_info *, int);
int (*lock_door)(struct cdrom_device_info *, int); int (*lock_door)(struct cdrom_device_info *, int);
int (*select_speed)(struct cdrom_device_info *, int); int (*select_speed)(struct cdrom_device_info *, unsigned long);
int (*get_last_session) (struct cdrom_device_info *, int (*get_last_session) (struct cdrom_device_info *,
struct cdrom_multisession *); struct cdrom_multisession *);
int (*get_mcn)(struct cdrom_device_info *, struct cdrom_mcn *); int (*get_mcn)(struct cdrom_device_info *, struct cdrom_mcn *);
...@@ -396,7 +396,7 @@ action need be taken, and the return value should be 0. ...@@ -396,7 +396,7 @@ action need be taken, and the return value should be 0.
:: ::
int select_speed(struct cdrom_device_info *cdi, int speed) int select_speed(struct cdrom_device_info *cdi, unsigned long speed)
Some CD-ROM drives are capable of changing their head-speed. There Some CD-ROM drives are capable of changing their head-speed. There
are several reasons for changing the speed of a CD-ROM drive. Badly are several reasons for changing the speed of a CD-ROM drive. Badly
......
...@@ -414,28 +414,40 @@ static char print_alua_state(unsigned char state) ...@@ -414,28 +414,40 @@ static char print_alua_state(unsigned char state)
} }
} }
static enum scsi_disposition alua_check_sense(struct scsi_device *sdev, static void alua_handle_state_transition(struct scsi_device *sdev)
struct scsi_sense_hdr *sense_hdr)
{ {
struct alua_dh_data *h = sdev->handler_data; struct alua_dh_data *h = sdev->handler_data;
struct alua_port_group *pg; struct alua_port_group *pg;
switch (sense_hdr->sense_key) {
case NOT_READY:
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
*/
rcu_read_lock(); rcu_read_lock();
pg = rcu_dereference(h->pg); pg = rcu_dereference(h->pg);
if (pg) if (pg)
pg->state = SCSI_ACCESS_STATE_TRANSITIONING; pg->state = SCSI_ACCESS_STATE_TRANSITIONING;
rcu_read_unlock(); rcu_read_unlock();
alua_check(sdev, false); alua_check(sdev, false);
}
static enum scsi_disposition alua_check_sense(struct scsi_device *sdev,
struct scsi_sense_hdr *sense_hdr)
{
switch (sense_hdr->sense_key) {
case NOT_READY:
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
*/
alua_handle_state_transition(sdev);
return NEEDS_RETRY; return NEEDS_RETRY;
} }
break; break;
case UNIT_ATTENTION: case UNIT_ATTENTION:
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
*/
alua_handle_state_transition(sdev);
return NEEDS_RETRY;
}
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) { if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
/* /*
* Power On, Reset, or Bus Device Reset. * Power On, Reset, or Bus Device Reset.
...@@ -502,7 +514,8 @@ static int alua_tur(struct scsi_device *sdev) ...@@ -502,7 +514,8 @@ static int alua_tur(struct scsi_device *sdev)
retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ, retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
ALUA_FAILOVER_RETRIES, &sense_hdr); ALUA_FAILOVER_RETRIES, &sense_hdr);
if (sense_hdr.sense_key == NOT_READY && if ((sense_hdr.sense_key == NOT_READY ||
sense_hdr.sense_key == UNIT_ATTENTION) &&
sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
return SCSI_DH_RETRY; return SCSI_DH_RETRY;
else if (retval) else if (retval)
......
...@@ -1364,7 +1364,7 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, ...@@ -1364,7 +1364,7 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
continue; continue;
if (i > sizeof(mr_sas_port->phy_mask) * 8) { if (i > sizeof(mr_sas_port->phy_mask) * 8) {
ioc_warn(mrioc, "skipping port %u, max allowed value is %lu\n", ioc_warn(mrioc, "skipping port %u, max allowed value is %zu\n",
i, sizeof(mr_sas_port->phy_mask) * 8); i, sizeof(mr_sas_port->phy_mask) * 8);
goto out_fail; goto out_fail;
} }
......
...@@ -302,8 +302,8 @@ struct _scsi_io_transfer { ...@@ -302,8 +302,8 @@ struct _scsi_io_transfer {
/** /**
* _scsih_set_debug_level - global setting of ioc->logging_level. * _scsih_set_debug_level - global setting of ioc->logging_level.
* @val: ? * @val: value of the parameter to be set
* @kp: ? * @kp: pointer to kernel_param structure
* *
* Note: The logging levels are defined in mpt3sas_debug.h. * Note: The logging levels are defined in mpt3sas_debug.h.
*/ */
......
...@@ -363,6 +363,7 @@ struct qedf_ctx { ...@@ -363,6 +363,7 @@ struct qedf_ctx {
#define QEDF_IN_RECOVERY 5 #define QEDF_IN_RECOVERY 5
#define QEDF_DBG_STOP_IO 6 #define QEDF_DBG_STOP_IO 6
#define QEDF_PROBING 8 #define QEDF_PROBING 8
#define QEDF_STAG_IN_PROGRESS 9
unsigned long flags; /* Miscellaneous state flags */ unsigned long flags; /* Miscellaneous state flags */
int fipvlan_retries; int fipvlan_retries;
u8 num_queues; u8 num_queues;
......
...@@ -318,11 +318,18 @@ static struct fc_seq *qedf_elsct_send(struct fc_lport *lport, u32 did, ...@@ -318,11 +318,18 @@ static struct fc_seq *qedf_elsct_send(struct fc_lport *lport, u32 did,
*/ */
if (resp == fc_lport_flogi_resp) { if (resp == fc_lport_flogi_resp) {
qedf->flogi_cnt++; qedf->flogi_cnt++;
qedf->flogi_pending++;
if (test_bit(QEDF_UNLOADING, &qedf->flags)) {
QEDF_ERR(&qedf->dbg_ctx, "Driver unloading\n");
qedf->flogi_pending = 0;
}
if (qedf->flogi_pending >= QEDF_FLOGI_RETRY_CNT) { if (qedf->flogi_pending >= QEDF_FLOGI_RETRY_CNT) {
schedule_delayed_work(&qedf->stag_work, 2); schedule_delayed_work(&qedf->stag_work, 2);
return NULL; return NULL;
} }
qedf->flogi_pending++;
return fc_elsct_send(lport, did, fp, op, qedf_flogi_resp, return fc_elsct_send(lport, did, fp, op, qedf_flogi_resp,
arg, timeout); arg, timeout);
} }
...@@ -912,13 +919,14 @@ void qedf_ctx_soft_reset(struct fc_lport *lport) ...@@ -912,13 +919,14 @@ void qedf_ctx_soft_reset(struct fc_lport *lport)
struct qedf_ctx *qedf; struct qedf_ctx *qedf;
struct qed_link_output if_link; struct qed_link_output if_link;
qedf = lport_priv(lport);
if (lport->vport) { if (lport->vport) {
clear_bit(QEDF_STAG_IN_PROGRESS, &qedf->flags);
printk_ratelimited("Cannot issue host reset on NPIV port.\n"); printk_ratelimited("Cannot issue host reset on NPIV port.\n");
return; return;
} }
qedf = lport_priv(lport);
qedf->flogi_pending = 0; qedf->flogi_pending = 0;
/* For host reset, essentially do a soft link up/down */ /* For host reset, essentially do a soft link up/down */
atomic_set(&qedf->link_state, QEDF_LINK_DOWN); atomic_set(&qedf->link_state, QEDF_LINK_DOWN);
...@@ -938,6 +946,7 @@ void qedf_ctx_soft_reset(struct fc_lport *lport) ...@@ -938,6 +946,7 @@ void qedf_ctx_soft_reset(struct fc_lport *lport)
if (!if_link.link_up) { if (!if_link.link_up) {
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
"Physical link is not up.\n"); "Physical link is not up.\n");
clear_bit(QEDF_STAG_IN_PROGRESS, &qedf->flags);
return; return;
} }
/* Flush and wait to make sure link down is processed */ /* Flush and wait to make sure link down is processed */
...@@ -950,6 +959,7 @@ void qedf_ctx_soft_reset(struct fc_lport *lport) ...@@ -950,6 +959,7 @@ void qedf_ctx_soft_reset(struct fc_lport *lport)
"Queue link up work.\n"); "Queue link up work.\n");
queue_delayed_work(qedf->link_update_wq, &qedf->link_update, queue_delayed_work(qedf->link_update_wq, &qedf->link_update,
0); 0);
clear_bit(QEDF_STAG_IN_PROGRESS, &qedf->flags);
} }
/* Reset the host by gracefully logging out and then logging back in */ /* Reset the host by gracefully logging out and then logging back in */
...@@ -3463,6 +3473,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) ...@@ -3463,6 +3473,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
} }
/* Start the Slowpath-process */ /* Start the Slowpath-process */
memset(&slowpath_params, 0, sizeof(struct qed_slowpath_params));
slowpath_params.int_mode = QED_INT_MODE_MSIX; slowpath_params.int_mode = QED_INT_MODE_MSIX;
slowpath_params.drv_major = QEDF_DRIVER_MAJOR_VER; slowpath_params.drv_major = QEDF_DRIVER_MAJOR_VER;
slowpath_params.drv_minor = QEDF_DRIVER_MINOR_VER; slowpath_params.drv_minor = QEDF_DRIVER_MINOR_VER;
...@@ -3721,6 +3732,7 @@ static void __qedf_remove(struct pci_dev *pdev, int mode) ...@@ -3721,6 +3732,7 @@ static void __qedf_remove(struct pci_dev *pdev, int mode)
{ {
struct qedf_ctx *qedf; struct qedf_ctx *qedf;
int rc; int rc;
int cnt = 0;
if (!pdev) { if (!pdev) {
QEDF_ERR(NULL, "pdev is NULL.\n"); QEDF_ERR(NULL, "pdev is NULL.\n");
...@@ -3738,6 +3750,17 @@ static void __qedf_remove(struct pci_dev *pdev, int mode) ...@@ -3738,6 +3750,17 @@ static void __qedf_remove(struct pci_dev *pdev, int mode)
return; return;
} }
stag_in_prog:
if (test_bit(QEDF_STAG_IN_PROGRESS, &qedf->flags)) {
QEDF_ERR(&qedf->dbg_ctx, "Stag in progress, cnt=%d.\n", cnt);
cnt++;
if (cnt < 5) {
msleep(500);
goto stag_in_prog;
}
}
if (mode != QEDF_MODE_RECOVERY) if (mode != QEDF_MODE_RECOVERY)
set_bit(QEDF_UNLOADING, &qedf->flags); set_bit(QEDF_UNLOADING, &qedf->flags);
...@@ -3997,6 +4020,24 @@ void qedf_stag_change_work(struct work_struct *work) ...@@ -3997,6 +4020,24 @@ void qedf_stag_change_work(struct work_struct *work)
struct qedf_ctx *qedf = struct qedf_ctx *qedf =
container_of(work, struct qedf_ctx, stag_work.work); container_of(work, struct qedf_ctx, stag_work.work);
if (!qedf) {
QEDF_ERR(&qedf->dbg_ctx, "qedf is NULL");
return;
}
if (test_bit(QEDF_IN_RECOVERY, &qedf->flags)) {
QEDF_ERR(&qedf->dbg_ctx,
"Already is in recovery, hence not calling software context reset.\n");
return;
}
if (test_bit(QEDF_UNLOADING, &qedf->flags)) {
QEDF_ERR(&qedf->dbg_ctx, "Driver unloading\n");
return;
}
set_bit(QEDF_STAG_IN_PROGRESS, &qedf->flags);
printk_ratelimited("[%s]:[%s:%d]:%d: Performing software context reset.", printk_ratelimited("[%s]:[%s:%d]:%d: Performing software context reset.",
dev_name(&qedf->pdev->dev), __func__, __LINE__, dev_name(&qedf->pdev->dev), __func__, __LINE__,
qedf->dbg_ctx.host_no); qedf->dbg_ctx.host_no);
......
...@@ -350,6 +350,13 @@ static int scsi_get_vpd_size(struct scsi_device *sdev, u8 page) ...@@ -350,6 +350,13 @@ static int scsi_get_vpd_size(struct scsi_device *sdev, u8 page)
if (result < SCSI_VPD_HEADER_SIZE) if (result < SCSI_VPD_HEADER_SIZE)
return 0; return 0;
if (result > sizeof(vpd)) {
dev_warn_once(&sdev->sdev_gendev,
"%s: long VPD page 0 length: %d bytes\n",
__func__, result);
result = sizeof(vpd);
}
result -= SCSI_VPD_HEADER_SIZE; result -= SCSI_VPD_HEADER_SIZE;
if (!memchr(&vpd[SCSI_VPD_HEADER_SIZE], page, result)) if (!memchr(&vpd[SCSI_VPD_HEADER_SIZE], page, result))
return 0; return 0;
......
...@@ -65,7 +65,7 @@ int sr_disk_status(struct cdrom_device_info *); ...@@ -65,7 +65,7 @@ int sr_disk_status(struct cdrom_device_info *);
int sr_get_last_session(struct cdrom_device_info *, struct cdrom_multisession *); int sr_get_last_session(struct cdrom_device_info *, struct cdrom_multisession *);
int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *); int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
int sr_reset(struct cdrom_device_info *); int sr_reset(struct cdrom_device_info *);
int sr_select_speed(struct cdrom_device_info *cdi, int speed); int sr_select_speed(struct cdrom_device_info *cdi, unsigned long speed);
int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
int sr_is_xa(Scsi_CD *); int sr_is_xa(Scsi_CD *);
......
...@@ -425,11 +425,14 @@ int sr_reset(struct cdrom_device_info *cdi) ...@@ -425,11 +425,14 @@ int sr_reset(struct cdrom_device_info *cdi)
return 0; return 0;
} }
int sr_select_speed(struct cdrom_device_info *cdi, int speed) int sr_select_speed(struct cdrom_device_info *cdi, unsigned long speed)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
struct packet_command cgc; struct packet_command cgc;
/* avoid exceeding the max speed or overflowing integer bounds */
speed = clamp(0, speed, 0xffff / 177);
if (speed == 0) if (speed == 0)
speed = 0xffff; /* set to max */ speed = 0xffff; /* set to max */
else else
......
...@@ -634,20 +634,20 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) ...@@ -634,20 +634,20 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd)
struct ufshcd_lrb *lrbp = &hba->lrb[tag]; struct ufshcd_lrb *lrbp = &hba->lrb[tag];
struct ufs_hw_queue *hwq; struct ufs_hw_queue *hwq;
unsigned long flags; unsigned long flags;
int err = FAILED; int err;
if (!ufshcd_cmd_inflight(lrbp->cmd)) { if (!ufshcd_cmd_inflight(lrbp->cmd)) {
dev_err(hba->dev, dev_err(hba->dev,
"%s: skip abort. cmd at tag %d already completed.\n", "%s: skip abort. cmd at tag %d already completed.\n",
__func__, tag); __func__, tag);
goto out; return FAILED;
} }
/* Skip task abort in case previous aborts failed and report failure */ /* Skip task abort in case previous aborts failed and report failure */
if (lrbp->req_abort_skip) { if (lrbp->req_abort_skip) {
dev_err(hba->dev, "%s: skip abort. tag %d failed earlier\n", dev_err(hba->dev, "%s: skip abort. tag %d failed earlier\n",
__func__, tag); __func__, tag);
goto out; return FAILED;
} }
hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd));
...@@ -659,7 +659,7 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) ...@@ -659,7 +659,7 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd)
*/ */
dev_err(hba->dev, "%s: cmd found in sq. hwq=%d, tag=%d\n", dev_err(hba->dev, "%s: cmd found in sq. hwq=%d, tag=%d\n",
__func__, hwq->id, tag); __func__, hwq->id, tag);
goto out; return FAILED;
} }
/* /*
...@@ -667,18 +667,17 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) ...@@ -667,18 +667,17 @@ int ufshcd_mcq_abort(struct scsi_cmnd *cmd)
* in the completion queue either. Query the device to see if * in the completion queue either. Query the device to see if
* the command is being processed in the device. * the command is being processed in the device.
*/ */
if (ufshcd_try_to_abort_task(hba, tag)) { err = ufshcd_try_to_abort_task(hba, tag);
if (err) {
dev_err(hba->dev, "%s: device abort failed %d\n", __func__, err); dev_err(hba->dev, "%s: device abort failed %d\n", __func__, err);
lrbp->req_abort_skip = true; lrbp->req_abort_skip = true;
goto out; return FAILED;
} }
err = SUCCESS;
spin_lock_irqsave(&hwq->cq_lock, flags); spin_lock_irqsave(&hwq->cq_lock, flags);
if (ufshcd_cmd_inflight(lrbp->cmd)) if (ufshcd_cmd_inflight(lrbp->cmd))
ufshcd_release_scsi_cmd(hba, lrbp); ufshcd_release_scsi_cmd(hba, lrbp);
spin_unlock_irqrestore(&hwq->cq_lock, flags); spin_unlock_irqrestore(&hwq->cq_lock, flags);
out: return SUCCESS;
return err;
} }
...@@ -77,7 +77,7 @@ struct cdrom_device_ops { ...@@ -77,7 +77,7 @@ struct cdrom_device_ops {
unsigned int clearing, int slot); unsigned int clearing, int slot);
int (*tray_move) (struct cdrom_device_info *, int); int (*tray_move) (struct cdrom_device_info *, int);
int (*lock_door) (struct cdrom_device_info *, int); int (*lock_door) (struct cdrom_device_info *, int);
int (*select_speed) (struct cdrom_device_info *, int); int (*select_speed) (struct cdrom_device_info *, unsigned long);
int (*get_last_session) (struct cdrom_device_info *, int (*get_last_session) (struct cdrom_device_info *,
struct cdrom_multisession *); struct cdrom_multisession *);
int (*get_mcn) (struct cdrom_device_info *, int (*get_mcn) (struct cdrom_device_info *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment