diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_ctl.c')
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 216 | 
1 files changed, 144 insertions, 72 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 2d4f85c9d7a..ba6ab170bdf 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -64,6 +64,9 @@  static struct fasync_struct *async_queue;  static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); +static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, +    u8 *issue_reset); +  /**   * enum block_state - blocking state   * @NON_BLOCKING: non blocking @@ -378,10 +381,22 @@ _ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp)  void  mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  { +	int i; +	u8 issue_reset; +  	switch (reset_phase) {  	case MPT2_IOC_PRE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); +		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { +			if (!(ioc->diag_buffer_status[i] & +			    MPT2_DIAG_BUFFER_IS_REGISTERED)) +				continue; +			if ((ioc->diag_buffer_status[i] & +			    MPT2_DIAG_BUFFER_IS_RELEASED)) +				continue; +			_ctl_send_release(ioc, i, &issue_reset); +		}  		break;  	case MPT2_IOC_AFTER_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " @@ -395,6 +410,17 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  	case MPT2_IOC_DONE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); + +		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { +			if (!(ioc->diag_buffer_status[i] & +			    MPT2_DIAG_BUFFER_IS_REGISTERED)) +				continue; +			if ((ioc->diag_buffer_status[i] & +			    MPT2_DIAG_BUFFER_IS_RELEASED)) +				continue; +			ioc->diag_buffer_status[i] |= +			    MPT2_DIAG_BUFFER_IS_DIAG_RESET; +		}  		break;  	}  } @@ -714,8 +740,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		if (tm_request->TaskType ==  		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { -			if (_ctl_do_task_abort(ioc, &karg, tm_request)) +			if (_ctl_do_task_abort(ioc, &karg, tm_request)) { +				mpt2sas_base_free_smid(ioc, smid);  				goto out; +			}  		}  		mutex_lock(&ioc->tm_cmds.mutex); @@ -915,9 +943,9 @@ _ctl_getiocinfo(void __user *arg)  	karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);  	karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);  	karg.firmware_version = ioc->facts.FWVersion.Word; -	strncpy(karg.driver_version, MPT2SAS_DRIVER_VERSION, -	    MPT2_IOCTL_VERSION_LENGTH); -	karg.driver_version[MPT2_IOCTL_VERSION_LENGTH - 1] = '\0'; +	strcpy(karg.driver_version, MPT2SAS_DRIVER_NAME); +	strcat(karg.driver_version, "-"); +	strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);  	karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);  	if (copy_to_user(arg, &karg, sizeof(karg))) { @@ -1551,81 +1579,38 @@ _ctl_diag_query(void __user *arg)  }  /** - * _ctl_diag_release - request to send Diag Release Message to firmware - * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING + * _ctl_send_release - Diag Release Message + * @ioc: per adapter object + * @buffer_type - specifies either TRACE or SNAPSHOT + * @issue_reset - specifies whether host reset is required.   * - * This allows ownership of the specified buffer to returned to the driver, - * allowing an application to read the buffer without fear that firmware is - * overwritting information in the buffer.   */ -static long -_ctl_diag_release(void __user *arg, enum block_state state) +static int +_ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  { -	struct mpt2_diag_release karg; -	struct MPT2SAS_ADAPTER *ioc; -	void *request_data; -	int rc;  	Mpi2DiagReleaseRequest_t *mpi_request;  	Mpi2DiagReleaseReply_t *mpi_reply; -	u8 buffer_type; -	unsigned long timeleft;  	u16 smid;  	u16 ioc_status; -	u8 issue_reset = 0; - -	if (copy_from_user(&karg, arg, sizeof(karg))) { -		printk(KERN_ERR "failure at %s:%d/%s()!\n", -		    __FILE__, __LINE__, __func__); -		return -EFAULT; -	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV; +	u32 ioc_state; +	int rc; +	unsigned long timeleft;  	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,  	    __func__)); -	buffer_type = karg.unique_id & 0x000000ff; -	if (!_ctl_diag_capability(ioc, buffer_type)) { -		printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " -		    "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); -		return -EPERM; -	} - -	if ((ioc->diag_buffer_status[buffer_type] & -	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { -		printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " -		    "registered\n", ioc->name, __func__, buffer_type); -		return -EINVAL; -	} - -	if (karg.unique_id != ioc->unique_id[buffer_type]) { -		printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " -		    "registered\n", ioc->name, __func__, karg.unique_id); -		return -EINVAL; -	} - -	if (ioc->diag_buffer_status[buffer_type] & -	    MPT2_DIAG_BUFFER_IS_RELEASED) { -		printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " -		    "is already released\n", ioc->name, __func__, -		    buffer_type); -		return 0; -	} - -	request_data = ioc->diag_buffer[buffer_type]; +	rc = 0; +	*issue_reset = 0; -	if (!request_data) { -		printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " -		    "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); -		return -ENOMEM; +	ioc_state = mpt2sas_base_get_iocstate(ioc, 1); +	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { +		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		    "skipping due to FAULT state\n", ioc->name, +		    __func__)); +		rc = -EAGAIN; +		goto out;  	} -	if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) -		return -EAGAIN; -	else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) -		return -ERESTARTSYS; -  	if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {  		printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",  		    ioc->name, __func__); @@ -1641,7 +1626,6 @@ _ctl_diag_release(void __user *arg, enum block_state state)  		goto out;  	} -	rc = 0;  	ioc->ctl_cmds.status = MPT2_CMD_PENDING;  	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); @@ -1660,8 +1644,9 @@ _ctl_diag_release(void __user *arg, enum block_state state)  		_debug_dump_mf(mpi_request,  		    sizeof(Mpi2DiagReleaseRequest_t)/4);  		if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) -			issue_reset = 1; -		goto issue_host_reset; +			*issue_reset = 1; +		rc = -EFAULT; +		goto out;  	}  	/* process the completed Reply Message Frame */ @@ -1687,14 +1672,101 @@ _ctl_diag_release(void __user *arg, enum block_state state)  		rc = -EFAULT;  	} - issue_host_reset: + out: +	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; +	return rc; +} + +/** + * _ctl_diag_release - request to send Diag Release Message to firmware + * @arg - user space buffer containing ioctl content + * @state - NON_BLOCKING or BLOCKING + * + * This allows ownership of the specified buffer to returned to the driver, + * allowing an application to read the buffer without fear that firmware is + * overwritting information in the buffer. + */ +static long +_ctl_diag_release(void __user *arg, enum block_state state) +{ +	struct mpt2_diag_release karg; +	struct MPT2SAS_ADAPTER *ioc; +	void *request_data; +	int rc; +	u8 buffer_type; +	u8 issue_reset = 0; + +	if (copy_from_user(&karg, arg, sizeof(karg))) { +		printk(KERN_ERR "failure at %s:%d/%s()!\n", +		    __FILE__, __LINE__, __func__); +		return -EFAULT; +	} +	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) +		return -ENODEV; + +	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	    __func__)); + +	buffer_type = karg.unique_id & 0x000000ff; +	if (!_ctl_diag_capability(ioc, buffer_type)) { +		printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " +		    "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); +		return -EPERM; +	} + +	if ((ioc->diag_buffer_status[buffer_type] & +	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { +		printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " +		    "registered\n", ioc->name, __func__, buffer_type); +		return -EINVAL; +	} + +	if (karg.unique_id != ioc->unique_id[buffer_type]) { +		printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " +		    "registered\n", ioc->name, __func__, karg.unique_id); +		return -EINVAL; +	} + +	if (ioc->diag_buffer_status[buffer_type] & +	    MPT2_DIAG_BUFFER_IS_RELEASED) { +		printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " +		    "is already released\n", ioc->name, __func__, +		    buffer_type); +		return 0; +	} + +	request_data = ioc->diag_buffer[buffer_type]; + +	if (!request_data) { +		printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " +		    "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); +		return -ENOMEM; +	} + +	/* buffers were released by due to host reset */ +	if ((ioc->diag_buffer_status[buffer_type] & +	    MPT2_DIAG_BUFFER_IS_DIAG_RESET)) { +		ioc->diag_buffer_status[buffer_type] |= +		    MPT2_DIAG_BUFFER_IS_RELEASED; +		ioc->diag_buffer_status[buffer_type] &= +		    ~MPT2_DIAG_BUFFER_IS_DIAG_RESET; +		printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " +		    "was released due to host reset\n", ioc->name, __func__, +		    buffer_type); +		return 0; +	} + +	if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) +		return -EAGAIN; +	else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) +		return -ERESTARTSYS; + +	rc = _ctl_send_release(ioc, buffer_type, &issue_reset); +  	if (issue_reset)  		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  		    FORCE_BIG_HAMMER); - out: - -	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;  	mutex_unlock(&ioc->ctl_cmds.mutex);  	return rc;  }  |