|
@@ -107,6 +107,72 @@ static int mtip_exec_internal_command(struct mtip_port *port,
|
|
|
gfp_t atomic,
|
|
|
unsigned long timeout);
|
|
|
|
|
|
+/*
|
|
|
+ * This function check_for_surprise_removal is called
|
|
|
+ * while card is removed from the system and it will
|
|
|
+ * read the vendor id from the configration space
|
|
|
+ *
|
|
|
+ * @pdev Pointer to the pci_dev structure.
|
|
|
+ *
|
|
|
+ * return value
|
|
|
+ * true if device removed, else false
|
|
|
+ */
|
|
|
+static bool mtip_check_surprise_removal(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ u16 vendor_id = 0;
|
|
|
+
|
|
|
+ /* Read the vendorID from the configuration space */
|
|
|
+ pci_read_config_word(pdev, 0x00, &vendor_id);
|
|
|
+ if (vendor_id == 0xFFFF)
|
|
|
+ return true; /* device removed */
|
|
|
+
|
|
|
+ return false; /* device present */
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This function is called for clean the pending command in the
|
|
|
+ * command slot during the surprise removal of device and return
|
|
|
+ * error to the upper layer.
|
|
|
+ *
|
|
|
+ * @dd Pointer to the DRIVER_DATA structure.
|
|
|
+ *
|
|
|
+ * return value
|
|
|
+ * None
|
|
|
+ */
|
|
|
+static void mtip_command_cleanup(struct driver_data *dd)
|
|
|
+{
|
|
|
+ int group = 0, commandslot = 0, commandindex = 0;
|
|
|
+ struct mtip_cmd *command;
|
|
|
+ struct mtip_port *port = dd->port;
|
|
|
+
|
|
|
+ for (group = 0; group < 4; group++) {
|
|
|
+ for (commandslot = 0; commandslot < 32; commandslot++) {
|
|
|
+ if (!(port->allocated[group] & (1 << commandslot)))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ commandindex = group << 5 | commandslot;
|
|
|
+ command = &port->commands[commandindex];
|
|
|
+
|
|
|
+ if (atomic_read(&command->active)
|
|
|
+ && (command->async_callback)) {
|
|
|
+ command->async_callback(command->async_data,
|
|
|
+ -ENODEV);
|
|
|
+ command->async_callback = NULL;
|
|
|
+ command->async_data = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ dma_unmap_sg(&port->dd->pdev->dev,
|
|
|
+ command->sg,
|
|
|
+ command->scatter_ents,
|
|
|
+ command->direction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ up(&port->cmd_slot);
|
|
|
+
|
|
|
+ atomic_set(&dd->drv_cleanup_done, true);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Obtain an empty command slot.
|
|
|
*
|
|
@@ -167,214 +233,72 @@ static inline void release_slot(struct mtip_port *port, int tag)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Issue a command to the hardware.
|
|
|
- *
|
|
|
- * Set the appropriate bit in the s_active and Command Issue hardware
|
|
|
- * registers, causing hardware command processing to begin.
|
|
|
- *
|
|
|
- * @port Pointer to the port structure.
|
|
|
- * @tag The tag of the command to be issued.
|
|
|
+ * Reset the HBA (without sleeping)
|
|
|
*
|
|
|
- * return value
|
|
|
- * None
|
|
|
- */
|
|
|
-static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag)
|
|
|
-{
|
|
|
- unsigned long flags = 0;
|
|
|
-
|
|
|
- atomic_set(&port->commands[tag].active, 1);
|
|
|
-
|
|
|
- spin_lock_irqsave(&port->cmd_issue_lock, flags);
|
|
|
-
|
|
|
- writel((1 << MTIP_TAG_BIT(tag)),
|
|
|
- port->s_active[MTIP_TAG_INDEX(tag)]);
|
|
|
- writel((1 << MTIP_TAG_BIT(tag)),
|
|
|
- port->cmd_issue[MTIP_TAG_INDEX(tag)]);
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&port->cmd_issue_lock, flags);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Called periodically to see if any read/write commands are
|
|
|
- * taking too long to complete.
|
|
|
+ * Just like hba_reset, except does not call sleep, so can be
|
|
|
+ * run from interrupt/tasklet context.
|
|
|
*
|
|
|
- * @data Pointer to the PORT data structure.
|
|
|
+ * @dd Pointer to the driver data structure.
|
|
|
*
|
|
|
* return value
|
|
|
- * None
|
|
|
+ * 0 The reset was successful.
|
|
|
+ * -1 The HBA Reset bit did not clear.
|
|
|
*/
|
|
|
-void mtip_timeout_function(unsigned long int data)
|
|
|
+static int hba_reset_nosleep(struct driver_data *dd)
|
|
|
{
|
|
|
- struct mtip_port *port = (struct mtip_port *) data;
|
|
|
- struct host_to_dev_fis *fis;
|
|
|
- struct mtip_cmd *command;
|
|
|
- int tag, cmdto_cnt = 0;
|
|
|
- unsigned int bit, group;
|
|
|
- unsigned int num_command_slots = port->dd->slot_groups * 32;
|
|
|
-
|
|
|
- if (unlikely(!port))
|
|
|
- return;
|
|
|
-
|
|
|
- if (atomic_read(&port->dd->resumeflag) == true) {
|
|
|
- mod_timer(&port->cmd_timer,
|
|
|
- jiffies + msecs_to_jiffies(30000));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (tag = 0; tag < num_command_slots; tag++) {
|
|
|
- /*
|
|
|
- * Skip internal command slot as it has
|
|
|
- * its own timeout mechanism
|
|
|
- */
|
|
|
- if (tag == MTIP_TAG_INTERNAL)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (atomic_read(&port->commands[tag].active) &&
|
|
|
- (time_after(jiffies, port->commands[tag].comp_time))) {
|
|
|
- group = tag >> 5;
|
|
|
- bit = tag & 0x1f;
|
|
|
-
|
|
|
- command = &port->commands[tag];
|
|
|
- fis = (struct host_to_dev_fis *) command->command;
|
|
|
-
|
|
|
- dev_warn(&port->dd->pdev->dev,
|
|
|
- "Timeout for command tag %d\n", tag);
|
|
|
-
|
|
|
- cmdto_cnt++;
|
|
|
- if (cmdto_cnt == 1)
|
|
|
- atomic_inc(&port->dd->eh_active);
|
|
|
-
|
|
|
- /*
|
|
|
- * Clear the completed bit. This should prevent
|
|
|
- * any interrupt handlers from trying to retire
|
|
|
- * the command.
|
|
|
- */
|
|
|
- writel(1 << bit, port->completed[group]);
|
|
|
+ unsigned long timeout;
|
|
|
|
|
|
- /* Call the async completion callback. */
|
|
|
- if (likely(command->async_callback))
|
|
|
- command->async_callback(command->async_data,
|
|
|
- -EIO);
|
|
|
- command->async_callback = NULL;
|
|
|
- command->comp_func = NULL;
|
|
|
+ /* Chip quirk: quiesce any chip function */
|
|
|
+ mdelay(10);
|
|
|
|
|
|
- /* Unmap the DMA scatter list entries */
|
|
|
- dma_unmap_sg(&port->dd->pdev->dev,
|
|
|
- command->sg,
|
|
|
- command->scatter_ents,
|
|
|
- command->direction);
|
|
|
+ /* Set the reset bit */
|
|
|
+ writel(HOST_RESET, dd->mmio + HOST_CTL);
|
|
|
|
|
|
- /*
|
|
|
- * Clear the allocated bit and active tag for the
|
|
|
- * command.
|
|
|
- */
|
|
|
- atomic_set(&port->commands[tag].active, 0);
|
|
|
- release_slot(port, tag);
|
|
|
+ /* Flush */
|
|
|
+ readl(dd->mmio + HOST_CTL);
|
|
|
|
|
|
- up(&port->cmd_slot);
|
|
|
- }
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Wait 10ms then spin for up to 1 second
|
|
|
+ * waiting for reset acknowledgement
|
|
|
+ */
|
|
|
+ timeout = jiffies + msecs_to_jiffies(1000);
|
|
|
+ mdelay(10);
|
|
|
+ while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
|
|
|
+ && time_before(jiffies, timeout))
|
|
|
+ mdelay(1);
|
|
|
|
|
|
- if (cmdto_cnt) {
|
|
|
- dev_warn(&port->dd->pdev->dev,
|
|
|
- "%d commands timed out: restarting port",
|
|
|
- cmdto_cnt);
|
|
|
- mtip_restart_port(port);
|
|
|
- atomic_dec(&port->dd->eh_active);
|
|
|
- }
|
|
|
+ if (readl(dd->mmio + HOST_CTL) & HOST_RESET)
|
|
|
+ return -1;
|
|
|
|
|
|
- /* Restart the timer */
|
|
|
- mod_timer(&port->cmd_timer,
|
|
|
- jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD));
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * IO completion function.
|
|
|
+ * Issue a command to the hardware.
|
|
|
*
|
|
|
- * This completion function is called by the driver ISR when a
|
|
|
- * command that was issued by the kernel completes. It first calls the
|
|
|
- * asynchronous completion function which normally calls back into the block
|
|
|
- * layer passing the asynchronous callback data, then unmaps the
|
|
|
- * scatter list associated with the completed command, and finally
|
|
|
- * clears the allocated bit associated with the completed command.
|
|
|
+ * Set the appropriate bit in the s_active and Command Issue hardware
|
|
|
+ * registers, causing hardware command processing to begin.
|
|
|
*
|
|
|
- * @port Pointer to the port data structure.
|
|
|
- * @tag Tag of the command.
|
|
|
- * @data Pointer to driver_data.
|
|
|
- * @status Completion status.
|
|
|
+ * @port Pointer to the port structure.
|
|
|
+ * @tag The tag of the command to be issued.
|
|
|
*
|
|
|
* return value
|
|
|
- * None
|
|
|
+ * None
|
|
|
*/
|
|
|
-static void mtip_async_complete(struct mtip_port *port,
|
|
|
- int tag,
|
|
|
- void *data,
|
|
|
- int status)
|
|
|
+static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag)
|
|
|
{
|
|
|
- struct mtip_cmd *command;
|
|
|
- struct driver_data *dd = data;
|
|
|
- int cb_status = status ? -EIO : 0;
|
|
|
-
|
|
|
- if (unlikely(!dd) || unlikely(!port))
|
|
|
- return;
|
|
|
-
|
|
|
- command = &port->commands[tag];
|
|
|
-
|
|
|
- if (unlikely(status == PORT_IRQ_TF_ERR)) {
|
|
|
- dev_warn(&port->dd->pdev->dev,
|
|
|
- "Command tag %d failed due to TFE\n", tag);
|
|
|
- }
|
|
|
-
|
|
|
- /* Upper layer callback */
|
|
|
- if (likely(command->async_callback))
|
|
|
- command->async_callback(command->async_data, cb_status);
|
|
|
-
|
|
|
- command->async_callback = NULL;
|
|
|
- command->comp_func = NULL;
|
|
|
-
|
|
|
- /* Unmap the DMA scatter list entries */
|
|
|
- dma_unmap_sg(&dd->pdev->dev,
|
|
|
- command->sg,
|
|
|
- command->scatter_ents,
|
|
|
- command->direction);
|
|
|
-
|
|
|
- /* Clear the allocated and active bits for the command */
|
|
|
- atomic_set(&port->commands[tag].active, 0);
|
|
|
- release_slot(port, tag);
|
|
|
+ unsigned long flags = 0;
|
|
|
|
|
|
- up(&port->cmd_slot);
|
|
|
-}
|
|
|
+ atomic_set(&port->commands[tag].active, 1);
|
|
|
|
|
|
-/*
|
|
|
- * Internal command completion callback function.
|
|
|
- *
|
|
|
- * This function is normally called by the driver ISR when an internal
|
|
|
- * command completed. This function signals the command completion by
|
|
|
- * calling complete().
|
|
|
- *
|
|
|
- * @port Pointer to the port data structure.
|
|
|
- * @tag Tag of the command that has completed.
|
|
|
- * @data Pointer to a completion structure.
|
|
|
- * @status Completion status.
|
|
|
- *
|
|
|
- * return value
|
|
|
- * None
|
|
|
- */
|
|
|
-static void mtip_completion(struct mtip_port *port,
|
|
|
- int tag,
|
|
|
- void *data,
|
|
|
- int status)
|
|
|
-{
|
|
|
- struct mtip_cmd *command = &port->commands[tag];
|
|
|
- struct completion *waiting = data;
|
|
|
- if (unlikely(status == PORT_IRQ_TF_ERR))
|
|
|
- dev_warn(&port->dd->pdev->dev,
|
|
|
- "Internal command %d completed with TFE\n", tag);
|
|
|
+ spin_lock_irqsave(&port->cmd_issue_lock, flags);
|
|
|
|
|
|
- command->async_callback = NULL;
|
|
|
- command->comp_func = NULL;
|
|
|
+ writel((1 << MTIP_TAG_BIT(tag)),
|
|
|
+ port->s_active[MTIP_TAG_INDEX(tag)]);
|
|
|
+ writel((1 << MTIP_TAG_BIT(tag)),
|
|
|
+ port->cmd_issue[MTIP_TAG_INDEX(tag)]);
|
|
|
|
|
|
- complete(waiting);
|
|
|
+ spin_unlock_irqrestore(&port->cmd_issue_lock, flags);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -496,56 +420,15 @@ static void mtip_init_port(struct mtip_port *port)
|
|
|
/* Clear SError */
|
|
|
writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR);
|
|
|
|
|
|
- /* reset the completed registers.*/
|
|
|
- for (i = 0; i < port->dd->slot_groups; i++)
|
|
|
- writel(0xFFFFFFFF, port->completed[i]);
|
|
|
-
|
|
|
- /* Clear any pending interrupts for this port */
|
|
|
- writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT);
|
|
|
-
|
|
|
- /* Enable port interrupts */
|
|
|
- writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reset the HBA (without sleeping)
|
|
|
- *
|
|
|
- * Just like hba_reset, except does not call sleep, so can be
|
|
|
- * run from interrupt/tasklet context.
|
|
|
- *
|
|
|
- * @dd Pointer to the driver data structure.
|
|
|
- *
|
|
|
- * return value
|
|
|
- * 0 The reset was successful.
|
|
|
- * -1 The HBA Reset bit did not clear.
|
|
|
- */
|
|
|
-int hba_reset_nosleep(struct driver_data *dd)
|
|
|
-{
|
|
|
- unsigned long timeout;
|
|
|
-
|
|
|
- /* Chip quirk: quiesce any chip function */
|
|
|
- mdelay(10);
|
|
|
-
|
|
|
- /* Set the reset bit */
|
|
|
- writel(HOST_RESET, dd->mmio + HOST_CTL);
|
|
|
-
|
|
|
- /* Flush */
|
|
|
- readl(dd->mmio + HOST_CTL);
|
|
|
-
|
|
|
- /*
|
|
|
- * Wait 10ms then spin for up to 1 second
|
|
|
- * waiting for reset acknowledgement
|
|
|
- */
|
|
|
- timeout = jiffies + msecs_to_jiffies(1000);
|
|
|
- mdelay(10);
|
|
|
- while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
|
|
|
- && time_before(jiffies, timeout))
|
|
|
- mdelay(1);
|
|
|
+ /* reset the completed registers.*/
|
|
|
+ for (i = 0; i < port->dd->slot_groups; i++)
|
|
|
+ writel(0xFFFFFFFF, port->completed[i]);
|
|
|
|
|
|
- if (readl(dd->mmio + HOST_CTL) & HOST_RESET)
|
|
|
- return -1;
|
|
|
+ /* Clear any pending interrupts for this port */
|
|
|
+ writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT);
|
|
|
|
|
|
- return 0;
|
|
|
+ /* Enable port interrupts */
|
|
|
+ writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -556,7 +439,7 @@ int hba_reset_nosleep(struct driver_data *dd)
|
|
|
* return value
|
|
|
* None
|
|
|
*/
|
|
|
-void mtip_restart_port(struct mtip_port *port)
|
|
|
+static void mtip_restart_port(struct mtip_port *port)
|
|
|
{
|
|
|
unsigned long timeout;
|
|
|
|
|
@@ -619,6 +502,189 @@ void mtip_restart_port(struct mtip_port *port)
|
|
|
mtip_enable_engine(port, 1);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Called periodically to see if any read/write commands are
|
|
|
+ * taking too long to complete.
|
|
|
+ *
|
|
|
+ * @data Pointer to the PORT data structure.
|
|
|
+ *
|
|
|
+ * return value
|
|
|
+ * None
|
|
|
+ */
|
|
|
+static void mtip_timeout_function(unsigned long int data)
|
|
|
+{
|
|
|
+ struct mtip_port *port = (struct mtip_port *) data;
|
|
|
+ struct host_to_dev_fis *fis;
|
|
|
+ struct mtip_cmd *command;
|
|
|
+ int tag, cmdto_cnt = 0;
|
|
|
+ unsigned int bit, group;
|
|
|
+ unsigned int num_command_slots = port->dd->slot_groups * 32;
|
|
|
+
|
|
|
+ if (unlikely(!port))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (atomic_read(&port->dd->resumeflag) == true) {
|
|
|
+ mod_timer(&port->cmd_timer,
|
|
|
+ jiffies + msecs_to_jiffies(30000));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (tag = 0; tag < num_command_slots; tag++) {
|
|
|
+ /*
|
|
|
+ * Skip internal command slot as it has
|
|
|
+ * its own timeout mechanism
|
|
|
+ */
|
|
|
+ if (tag == MTIP_TAG_INTERNAL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (atomic_read(&port->commands[tag].active) &&
|
|
|
+ (time_after(jiffies, port->commands[tag].comp_time))) {
|
|
|
+ group = tag >> 5;
|
|
|
+ bit = tag & 0x1f;
|
|
|
+
|
|
|
+ command = &port->commands[tag];
|
|
|
+ fis = (struct host_to_dev_fis *) command->command;
|
|
|
+
|
|
|
+ dev_warn(&port->dd->pdev->dev,
|
|
|
+ "Timeout for command tag %d\n", tag);
|
|
|
+
|
|
|
+ cmdto_cnt++;
|
|
|
+ if (cmdto_cnt == 1)
|
|
|
+ atomic_inc(&port->dd->eh_active);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Clear the completed bit. This should prevent
|
|
|
+ * any interrupt handlers from trying to retire
|
|
|
+ * the command.
|
|
|
+ */
|
|
|
+ writel(1 << bit, port->completed[group]);
|
|
|
+
|
|
|
+ /* Call the async completion callback. */
|
|
|
+ if (likely(command->async_callback))
|
|
|
+ command->async_callback(command->async_data,
|
|
|
+ -EIO);
|
|
|
+ command->async_callback = NULL;
|
|
|
+ command->comp_func = NULL;
|
|
|
+
|
|
|
+ /* Unmap the DMA scatter list entries */
|
|
|
+ dma_unmap_sg(&port->dd->pdev->dev,
|
|
|
+ command->sg,
|
|
|
+ command->scatter_ents,
|
|
|
+ command->direction);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Clear the allocated bit and active tag for the
|
|
|
+ * command.
|
|
|
+ */
|
|
|
+ atomic_set(&port->commands[tag].active, 0);
|
|
|
+ release_slot(port, tag);
|
|
|
+
|
|
|
+ up(&port->cmd_slot);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cmdto_cnt) {
|
|
|
+ dev_warn(&port->dd->pdev->dev,
|
|
|
+ "%d commands timed out: restarting port",
|
|
|
+ cmdto_cnt);
|
|
|
+ mtip_restart_port(port);
|
|
|
+ atomic_dec(&port->dd->eh_active);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Restart the timer */
|
|
|
+ mod_timer(&port->cmd_timer,
|
|
|
+ jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * IO completion function.
|
|
|
+ *
|
|
|
+ * This completion function is called by the driver ISR when a
|
|
|
+ * command that was issued by the kernel completes. It first calls the
|
|
|
+ * asynchronous completion function which normally calls back into the block
|
|
|
+ * layer passing the asynchronous callback data, then unmaps the
|
|
|
+ * scatter list associated with the completed command, and finally
|
|
|
+ * clears the allocated bit associated with the completed command.
|
|
|
+ *
|
|
|
+ * @port Pointer to the port data structure.
|
|
|
+ * @tag Tag of the command.
|
|
|
+ * @data Pointer to driver_data.
|
|
|
+ * @status Completion status.
|
|
|
+ *
|
|
|
+ * return value
|
|
|
+ * None
|
|
|
+ */
|
|
|
+static void mtip_async_complete(struct mtip_port *port,
|
|
|
+ int tag,
|
|
|
+ void *data,
|
|
|
+ int status)
|
|
|
+{
|
|
|
+ struct mtip_cmd *command;
|
|
|
+ struct driver_data *dd = data;
|
|
|
+ int cb_status = status ? -EIO : 0;
|
|
|
+
|
|
|
+ if (unlikely(!dd) || unlikely(!port))
|
|
|
+ return;
|
|
|
+
|
|
|
+ command = &port->commands[tag];
|
|
|
+
|
|
|
+ if (unlikely(status == PORT_IRQ_TF_ERR)) {
|
|
|
+ dev_warn(&port->dd->pdev->dev,
|
|
|
+ "Command tag %d failed due to TFE\n", tag);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Upper layer callback */
|
|
|
+ if (likely(command->async_callback))
|
|
|
+ command->async_callback(command->async_data, cb_status);
|
|
|
+
|
|
|
+ command->async_callback = NULL;
|
|
|
+ command->comp_func = NULL;
|
|
|
+
|
|
|
+ /* Unmap the DMA scatter list entries */
|
|
|
+ dma_unmap_sg(&dd->pdev->dev,
|
|
|
+ command->sg,
|
|
|
+ command->scatter_ents,
|
|
|
+ command->direction);
|
|
|
+
|
|
|
+ /* Clear the allocated and active bits for the command */
|
|
|
+ atomic_set(&port->commands[tag].active, 0);
|
|
|
+ release_slot(port, tag);
|
|
|
+
|
|
|
+ up(&port->cmd_slot);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Internal command completion callback function.
|
|
|
+ *
|
|
|
+ * This function is normally called by the driver ISR when an internal
|
|
|
+ * command completed. This function signals the command completion by
|
|
|
+ * calling complete().
|
|
|
+ *
|
|
|
+ * @port Pointer to the port data structure.
|
|
|
+ * @tag Tag of the command that has completed.
|
|
|
+ * @data Pointer to a completion structure.
|
|
|
+ * @status Completion status.
|
|
|
+ *
|
|
|
+ * return value
|
|
|
+ * None
|
|
|
+ */
|
|
|
+static void mtip_completion(struct mtip_port *port,
|
|
|
+ int tag,
|
|
|
+ void *data,
|
|
|
+ int status)
|
|
|
+{
|
|
|
+ struct mtip_cmd *command = &port->commands[tag];
|
|
|
+ struct completion *waiting = data;
|
|
|
+ if (unlikely(status == PORT_IRQ_TF_ERR))
|
|
|
+ dev_warn(&port->dd->pdev->dev,
|
|
|
+ "Internal command %d completed with TFE\n", tag);
|
|
|
+
|
|
|
+ command->async_callback = NULL;
|
|
|
+ command->comp_func = NULL;
|
|
|
+
|
|
|
+ complete(waiting);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Helper function for tag logging
|
|
|
*/
|
|
@@ -1276,7 +1342,7 @@ static int mtip_standby_immediate(struct mtip_port *port)
|
|
|
* 1 Capacity was returned successfully.
|
|
|
* 0 The identify information is invalid.
|
|
|
*/
|
|
|
-bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors)
|
|
|
+static bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors)
|
|
|
{
|
|
|
struct mtip_port *port = dd->port;
|
|
|
u64 total, raw0, raw1, raw2, raw3;
|
|
@@ -1423,7 +1489,7 @@ static inline void fill_command_sg(struct driver_data *dd,
|
|
|
* return value 0 The command completed successfully.
|
|
|
* return value -1 An error occurred while executing the command.
|
|
|
*/
|
|
|
-int exec_drive_task(struct mtip_port *port, u8 *command)
|
|
|
+static int exec_drive_task(struct mtip_port *port, u8 *command)
|
|
|
{
|
|
|
struct host_to_dev_fis fis;
|
|
|
struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG);
|
|
@@ -1499,8 +1565,8 @@ int exec_drive_task(struct mtip_port *port, u8 *command)
|
|
|
* data to the user space buffer.
|
|
|
* return value -1 An error occurred while executing the command.
|
|
|
*/
|
|
|
-int exec_drive_command(struct mtip_port *port, u8 *command,
|
|
|
- void __user *user_buffer)
|
|
|
+static int exec_drive_command(struct mtip_port *port, u8 *command,
|
|
|
+ void __user *user_buffer)
|
|
|
{
|
|
|
struct host_to_dev_fis fis;
|
|
|
struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG);
|
|
@@ -2020,15 +2086,9 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd,
|
|
|
* return value
|
|
|
* None
|
|
|
*/
|
|
|
-void mtip_hw_submit_io(struct driver_data *dd,
|
|
|
- sector_t start,
|
|
|
- int nsect,
|
|
|
- int nents,
|
|
|
- int tag,
|
|
|
- void *callback,
|
|
|
- void *data,
|
|
|
- int barrier,
|
|
|
- int dir)
|
|
|
+static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
|
|
|
+ int nsect, int nents, int tag, void *callback,
|
|
|
+ void *data, int barrier, int dir)
|
|
|
{
|
|
|
struct host_to_dev_fis *fis;
|
|
|
struct mtip_port *port = dd->port;
|
|
@@ -2115,7 +2175,7 @@ void mtip_hw_submit_io(struct driver_data *dd,
|
|
|
* return value
|
|
|
* None
|
|
|
*/
|
|
|
-void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
|
|
|
+static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
|
|
|
{
|
|
|
release_slot(dd->port, tag);
|
|
|
}
|
|
@@ -2131,8 +2191,8 @@ void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
|
|
|
* Pointer to the scatter list for the allocated command slot
|
|
|
* or NULL if no command slots are available.
|
|
|
*/
|
|
|
-struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
|
|
|
- int *tag)
|
|
|
+static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
|
|
|
+ int *tag)
|
|
|
{
|
|
|
/*
|
|
|
* It is possible that, even with this semaphore, a thread
|
|
@@ -2216,7 +2276,7 @@ static DEVICE_ATTR(registers, S_IRUGO, hw_show_registers, NULL);
|
|
|
* 0 Operation completed successfully.
|
|
|
* -EINVAL Invalid parameter.
|
|
|
*/
|
|
|
-int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
|
|
|
+static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
|
|
|
{
|
|
|
if (!kobj || !dd)
|
|
|
return -EINVAL;
|
|
@@ -2237,7 +2297,7 @@ int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
|
|
|
* 0 Operation completed successfully.
|
|
|
* -EINVAL Invalid parameter.
|
|
|
*/
|
|
|
-int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
|
|
|
+static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
|
|
|
{
|
|
|
if (!kobj || !dd)
|
|
|
return -EINVAL;
|
|
@@ -2385,7 +2445,7 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd)
|
|
|
* return value
|
|
|
* 0 on success, else an error code.
|
|
|
*/
|
|
|
-int mtip_hw_init(struct driver_data *dd)
|
|
|
+static int mtip_hw_init(struct driver_data *dd)
|
|
|
{
|
|
|
int i;
|
|
|
int rv;
|
|
@@ -2586,7 +2646,7 @@ out1:
|
|
|
* return value
|
|
|
* 0
|
|
|
*/
|
|
|
-int mtip_hw_exit(struct driver_data *dd)
|
|
|
+static int mtip_hw_exit(struct driver_data *dd)
|
|
|
{
|
|
|
/*
|
|
|
* Send standby immediate (E0h) to the drive so that it
|
|
@@ -2634,7 +2694,7 @@ int mtip_hw_exit(struct driver_data *dd)
|
|
|
* return value
|
|
|
* 0
|
|
|
*/
|
|
|
-int mtip_hw_shutdown(struct driver_data *dd)
|
|
|
+static int mtip_hw_shutdown(struct driver_data *dd)
|
|
|
{
|
|
|
/*
|
|
|
* Send standby immediate (E0h) to the drive so that it
|
|
@@ -2657,7 +2717,7 @@ int mtip_hw_shutdown(struct driver_data *dd)
|
|
|
* 0 Suspend was successful
|
|
|
* -EFAULT Suspend was not successful
|
|
|
*/
|
|
|
-int mtip_hw_suspend(struct driver_data *dd)
|
|
|
+static int mtip_hw_suspend(struct driver_data *dd)
|
|
|
{
|
|
|
/*
|
|
|
* Send standby immediate (E0h) to the drive
|
|
@@ -2689,7 +2749,7 @@ int mtip_hw_suspend(struct driver_data *dd)
|
|
|
* 0 Resume was successful
|
|
|
* -EFAULT Resume was not successful
|
|
|
*/
|
|
|
-int mtip_hw_resume(struct driver_data *dd)
|
|
|
+static int mtip_hw_resume(struct driver_data *dd)
|
|
|
{
|
|
|
/* Perform any needed hardware setup steps */
|
|
|
hba_setup(dd);
|
|
@@ -2715,50 +2775,6 @@ int mtip_hw_resume(struct driver_data *dd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * This function is called for clean the pending command in the
|
|
|
- * command slot during the surprise removal of device and return
|
|
|
- * error to the upper layer.
|
|
|
- *
|
|
|
- * @dd Pointer to the DRIVER_DATA structure.
|
|
|
- *
|
|
|
- * return value
|
|
|
- * None
|
|
|
- */
|
|
|
-void mtip_command_cleanup(struct driver_data *dd)
|
|
|
-{
|
|
|
- int group = 0, commandslot = 0, commandindex = 0;
|
|
|
- struct mtip_cmd *command;
|
|
|
- struct mtip_port *port = dd->port;
|
|
|
-
|
|
|
- for (group = 0; group < 4; group++) {
|
|
|
- for (commandslot = 0; commandslot < 32; commandslot++) {
|
|
|
- if (!(port->allocated[group] & (1 << commandslot)))
|
|
|
- continue;
|
|
|
-
|
|
|
- commandindex = group << 5 | commandslot;
|
|
|
- command = &port->commands[commandindex];
|
|
|
-
|
|
|
- if (atomic_read(&command->active)
|
|
|
- && (command->async_callback)) {
|
|
|
- command->async_callback(command->async_data,
|
|
|
- -ENODEV);
|
|
|
- command->async_callback = NULL;
|
|
|
- command->async_data = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- dma_unmap_sg(&port->dd->pdev->dev,
|
|
|
- command->sg,
|
|
|
- command->scatter_ents,
|
|
|
- command->direction);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- up(&port->cmd_slot);
|
|
|
-
|
|
|
- atomic_set(&dd->drv_cleanup_done, true);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Helper function for reusing disk name
|
|
|
* upon hot insertion.
|
|
@@ -3037,7 +3053,7 @@ static int mtip_make_request(struct request_queue *queue, struct bio *bio)
|
|
|
* return value
|
|
|
* 0 on success else an error code.
|
|
|
*/
|
|
|
-int mtip_block_initialize(struct driver_data *dd)
|
|
|
+static int mtip_block_initialize(struct driver_data *dd)
|
|
|
{
|
|
|
int rv = 0;
|
|
|
sector_t capacity;
|
|
@@ -3168,7 +3184,7 @@ protocol_init_error:
|
|
|
* return value
|
|
|
* 0
|
|
|
*/
|
|
|
-int mtip_block_remove(struct driver_data *dd)
|
|
|
+static int mtip_block_remove(struct driver_data *dd)
|
|
|
{
|
|
|
struct kobject *kobj;
|
|
|
/* Clean up the sysfs attributes managed by the protocol layer. */
|
|
@@ -3205,7 +3221,7 @@ int mtip_block_remove(struct driver_data *dd)
|
|
|
* return value
|
|
|
* 0
|
|
|
*/
|
|
|
-int mtip_block_shutdown(struct driver_data *dd)
|
|
|
+static int mtip_block_shutdown(struct driver_data *dd)
|
|
|
{
|
|
|
dev_info(&dd->pdev->dev,
|
|
|
"Shutting down %s ...\n", dd->disk->disk_name);
|
|
@@ -3220,7 +3236,7 @@ int mtip_block_shutdown(struct driver_data *dd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int mtip_block_suspend(struct driver_data *dd)
|
|
|
+static int mtip_block_suspend(struct driver_data *dd)
|
|
|
{
|
|
|
dev_info(&dd->pdev->dev,
|
|
|
"Suspending %s ...\n", dd->disk->disk_name);
|
|
@@ -3228,7 +3244,7 @@ int mtip_block_suspend(struct driver_data *dd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int mtip_block_resume(struct driver_data *dd)
|
|
|
+static int mtip_block_resume(struct driver_data *dd)
|
|
|
{
|
|
|
dev_info(&dd->pdev->dev, "Resuming %s ...\n",
|
|
|
dd->disk->disk_name);
|
|
@@ -3479,28 +3495,6 @@ static void mtip_pci_shutdown(struct pci_dev *pdev)
|
|
|
mtip_block_shutdown(dd);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * This function check_for_surprise_removal is called
|
|
|
- * while card is removed from the system and it will
|
|
|
- * read the vendor id from the configration space
|
|
|
- *
|
|
|
- * @pdev Pointer to the pci_dev structure.
|
|
|
- *
|
|
|
- * return value
|
|
|
- * true if device removed, else false
|
|
|
- */
|
|
|
-bool mtip_check_surprise_removal(struct pci_dev *pdev)
|
|
|
-{
|
|
|
- u16 vendor_id = 0;
|
|
|
-
|
|
|
- /* Read the vendorID from the configuration space */
|
|
|
- pci_read_config_word(pdev, 0x00, &vendor_id);
|
|
|
- if (vendor_id == 0xFFFF)
|
|
|
- return true; /* device removed */
|
|
|
-
|
|
|
- return false; /* device present */
|
|
|
-}
|
|
|
-
|
|
|
/* Table of device ids supported by this driver. */
|
|
|
static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = {
|
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) },
|