|
@@ -64,6 +64,9 @@
|
|
static struct fasync_struct *async_queue;
|
|
static struct fasync_struct *async_queue;
|
|
static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait);
|
|
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
|
|
* enum block_state - blocking state
|
|
* @NON_BLOCKING: non blocking
|
|
* @NON_BLOCKING: non blocking
|
|
@@ -378,10 +381,22 @@ _ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp)
|
|
void
|
|
void
|
|
mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
|
|
mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
|
|
{
|
|
{
|
|
|
|
+ int i;
|
|
|
|
+ u8 issue_reset;
|
|
|
|
+
|
|
switch (reset_phase) {
|
|
switch (reset_phase) {
|
|
case MPT2_IOC_PRE_RESET:
|
|
case MPT2_IOC_PRE_RESET:
|
|
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
|
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
|
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
|
|
"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;
|
|
break;
|
|
case MPT2_IOC_AFTER_RESET:
|
|
case MPT2_IOC_AFTER_RESET:
|
|
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
|
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:
|
|
case MPT2_IOC_DONE_RESET:
|
|
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
|
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
|
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
|
|
"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;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1553,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;
|
|
Mpi2DiagReleaseRequest_t *mpi_request;
|
|
Mpi2DiagReleaseReply_t *mpi_reply;
|
|
Mpi2DiagReleaseReply_t *mpi_reply;
|
|
- u8 buffer_type;
|
|
|
|
- unsigned long timeleft;
|
|
|
|
u16 smid;
|
|
u16 smid;
|
|
u16 ioc_status;
|
|
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,
|
|
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
|
|
__func__));
|
|
__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) {
|
|
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
|
|
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
|
|
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
|
|
ioc->name, __func__);
|
|
ioc->name, __func__);
|
|
@@ -1643,7 +1626,6 @@ _ctl_diag_release(void __user *arg, enum block_state state)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- rc = 0;
|
|
|
|
ioc->ctl_cmds.status = MPT2_CMD_PENDING;
|
|
ioc->ctl_cmds.status = MPT2_CMD_PENDING;
|
|
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
|
|
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
|
|
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
|
|
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
|
|
@@ -1662,8 +1644,9 @@ _ctl_diag_release(void __user *arg, enum block_state state)
|
|
_debug_dump_mf(mpi_request,
|
|
_debug_dump_mf(mpi_request,
|
|
sizeof(Mpi2DiagReleaseRequest_t)/4);
|
|
sizeof(Mpi2DiagReleaseRequest_t)/4);
|
|
if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
|
|
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 */
|
|
/* process the completed Reply Message Frame */
|
|
@@ -1689,14 +1672,101 @@ _ctl_diag_release(void __user *arg, enum block_state state)
|
|
rc = -EFAULT;
|
|
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)
|
|
if (issue_reset)
|
|
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
|
|
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
|
|
FORCE_BIG_HAMMER);
|
|
FORCE_BIG_HAMMER);
|
|
|
|
|
|
- out:
|
|
|
|
-
|
|
|
|
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
|
|
|
|
mutex_unlock(&ioc->ctl_cmds.mutex);
|
|
mutex_unlock(&ioc->ctl_cmds.mutex);
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|