Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 155dd4c7 authored by Kashyap, Desai's avatar Kashyap, Desai Committed by James Bottomley
Browse files

[SCSI] mpt2sas: Prevent sending command to FW while Host Reset



This patch renames the flag for indicating host reset from
ioc_reset_in_progress to shost_recovery. It also removes the spin locks
surrounding the setting of this flag, which are unnecessary.   Sanity checks on
the shost_recovery flag were added thru out the code so as to prevent sending
firmware commands during host reset.  Also, the setting of the shost state to
SHOST_RECOVERY was removed to prevent deadlocks, this is actually better
handled by the shost_recovery flag.

Signed-off-by: default avatarKashyap Desai <kashyap.desai@lsi.com>
Reviewed-by: default avatarEric Moore <Eric.moore@lsi.com>
Cc: Stable Tree <stable@kernel.org>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent cd4e12e8
Loading
Loading
Loading
Loading
+3 −10
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ _base_fault_reset_work(struct work_struct *work)
	int rc;

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->ioc_reset_in_progress)
	if (ioc->shost_recovery)
		goto rearm_timer;
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

@@ -3501,20 +3501,13 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
	    __func__));

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->ioc_reset_in_progress) {
	if (ioc->shost_recovery) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
		printk(MPT2SAS_ERR_FMT "%s: busy\n",
		    ioc->name, __func__);
		return -EBUSY;
	}
	ioc->ioc_reset_in_progress = 1;
	ioc->shost_recovery = 1;
	if (ioc->shost->shost_state == SHOST_RUNNING) {
		/* set back to SHOST_RUNNING in mpt2sas_scsih.c */
		scsi_host_set_state(ioc->shost, SHOST_RECOVERY);
		printk(MPT2SAS_INFO_FMT "putting controller into "
		    "SHOST_RECOVERY\n", ioc->name);
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	_base_reset_handler(ioc, MPT2_IOC_PRE_RESET);
@@ -3534,7 +3527,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
	    ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	ioc->ioc_reset_in_progress = 0;
	ioc->shost_recovery = 0;
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	if (!r)
+1 −2
Original line number Diff line number Diff line
@@ -432,7 +432,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
 * @fw_event_list: list of fw events
 * @aen_event_read_flag: event log was read
 * @broadcast_aen_busy: broadcast aen waiting to be serviced
 * @ioc_reset_in_progress: host reset in progress
 * @shost_recovery: host reset in progress
 * @ioc_reset_in_progress_lock:
 * @ioc_link_reset_in_progress: phy/hard reset in progress
 * @ignore_loginfos: ignore loginfos during task managment
@@ -545,7 +545,6 @@ struct MPT2SAS_ADAPTER {
	 /* misc flags */
	int		aen_event_read_flag;
	u8		broadcast_aen_busy;
	u8		ioc_reset_in_progress;
	u8		shost_recovery;
	spinlock_t 	ioc_reset_in_progress_lock;
	u8		ioc_link_reset_in_progress;
+2 −14
Original line number Diff line number Diff line
@@ -1963,7 +1963,6 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
{
	enum block_state state;
	long ret = -EINVAL;
	unsigned long flags;

	state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING :
	    BLOCKING;
@@ -1989,13 +1988,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
		    !ioc)
			return -ENODEV;

		spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
		if (ioc->shost_recovery) {
			spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
			    flags);
		if (ioc->shost_recovery)
			return -EAGAIN;
		}
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
			uarg = arg;
@@ -2098,7 +2092,6 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
	struct mpt2_ioctl_command karg;
	struct MPT2SAS_ADAPTER *ioc;
	enum block_state state;
	unsigned long flags;

	if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
		return -EINVAL;
@@ -2113,13 +2106,8 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
	if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
		return -ENODEV;

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->shost_recovery) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
		    flags);
	if (ioc->shost_recovery)
		return -EAGAIN;
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
	karg.hdr.ioc_number = karg32.hdr.ioc_number;
+24 −16
Original line number Diff line number Diff line
@@ -1785,17 +1785,18 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
	u32 ioc_state;
	unsigned long timeleft;
	u8 VF_ID = 0;
	unsigned long flags;

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED ||
	    ioc->shost_recovery) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
		printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
		    __func__, ioc->name);
		return;
	}

	if (ioc->shost_recovery) {
		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
		    __func__, ioc->name);
		return;
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
	if (ioc_state & MPI2_DOORBELL_USED) {
@@ -2553,7 +2554,6 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
	Mpi2SCSIIORequest_t *mpi_request;
	u32 mpi_control;
	u16 smid;
	unsigned long flags;

	scmd->scsi_done = done;
	sas_device_priv_data = scmd->device->hostdata;
@@ -2572,13 +2572,10 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
	}

	/* see if we are busy with task managment stuff */
	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (sas_target_priv_data->tm_busy ||
	    ioc->shost_recovery || ioc->ioc_link_reset_in_progress) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
	if (sas_target_priv_data->tm_busy)
		return SCSI_MLQUEUE_DEVICE_BUSY;
	else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
		return SCSI_MLQUEUE_HOST_BUSY;
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	if (scmd->sc_data_direction == DMA_FROM_DEVICE)
		mpi_control = MPI2_SCSIIO_CONTROL_READ;
@@ -3374,6 +3371,9 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
	if (!handle)
		return -1;

	if (ioc->shost_recovery)
		return -1;

	if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
	    MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -3510,6 +3510,9 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
	struct _sas_node *sas_expander;
	unsigned long flags;

	if (ioc->shost_recovery)
		return;

	spin_lock_irqsave(&ioc->sas_node_lock, flags);
	sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@@ -3681,6 +3684,8 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
		mutex_unlock(&ioc->tm_cmds.mutex);
		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
		    "done: handle(0x%04x)\n", ioc->name, device_handle));
		if (ioc->shost_recovery)
			goto out;
	}

	/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
@@ -3846,6 +3851,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
			    "expander event\n", ioc->name));
			return;
		}
		if (ioc->shost_recovery)
			return;
		if (event_data->PHY[i].PhyStatus &
		    MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
			continue;
@@ -5217,13 +5224,10 @@ _firmware_event_work(struct work_struct *work)
	}
	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->shost_recovery) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
		_scsih_fw_event_requeue(ioc, fw_event, 1000);
		return;
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	switch (fw_event->event) {
	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
@@ -5425,6 +5429,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
			if (!sas_device)
				continue;
			_scsih_remove_device(ioc, sas_device->handle);
			if (ioc->shost_recovery)
				return;
			goto retry_device_search;
		}
	}
@@ -5446,6 +5452,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
			if (!expander_sibling)
				continue;
			_scsih_expander_remove(ioc, expander_sibling->handle);
			if (ioc->shost_recovery)
				return;
			goto retry_expander_search;
		}
	}
+17 −12
Original line number Diff line number Diff line
@@ -140,11 +140,18 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
	u32 device_info;
	u32 ioc_status;

	if (ioc->shost_recovery) {
		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
		    __func__, ioc->name);
		return -EFAULT;
	}

	if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",

		    ioc->name, __FILE__, __LINE__, __func__);
		return -1;
		return -ENXIO;
	}

	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
@@ -153,7 +160,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
		printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
		    "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
		     __FILE__, __LINE__, __func__);
		return -1;
		return -EIO;
	}

	memset(identify, 0, sizeof(identify));
@@ -288,21 +295,17 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
	void *psge;
	u32 sgl_flags;
	u8 issue_reset = 0;
	unsigned long flags;
	void *data_out = NULL;
	dma_addr_t data_out_dma;
	u32 sz;
	u64 *sas_address_le;
	u16 wait_state_count;

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->ioc_reset_in_progress) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->shost_recovery) {
		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
		    __func__, ioc->name);
		return -EFAULT;
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	mutex_lock(&ioc->transport_cmds.mutex);

@@ -806,6 +809,12 @@ mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc,
	struct _sas_node *sas_node;
	struct _sas_phy *mpt2sas_phy;

	if (ioc->shost_recovery) {
		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
			__func__, ioc->name);
		return;
	}

	spin_lock_irqsave(&ioc->sas_node_lock, flags);
	sas_node = _transport_sas_node_find_by_handle(ioc, handle);
	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@@ -1025,7 +1034,6 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
	void *psge;
	u32 sgl_flags;
	u8 issue_reset = 0;
	unsigned long flags;
	dma_addr_t dma_addr_in = 0;
	dma_addr_t dma_addr_out = 0;
	u16 wait_state_count;
@@ -1045,14 +1053,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
		return -EINVAL;
	}

	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->ioc_reset_in_progress) {
		spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
	if (ioc->shost_recovery) {
		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
		    __func__, ioc->name);
		return -EFAULT;
	}
	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);

	rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
	if (rc)