|
@@ -99,6 +99,7 @@ static unsigned int ipr_debug = 0;
|
|
|
static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS;
|
|
|
static unsigned int ipr_dual_ioa_raid = 1;
|
|
|
static unsigned int ipr_number_of_msix = 2;
|
|
|
+static unsigned int ipr_fast_reboot;
|
|
|
static DEFINE_SPINLOCK(ipr_driver_lock);
|
|
|
|
|
|
/* This table describes the differences between DMA controller chips */
|
|
@@ -221,6 +222,8 @@ MODULE_PARM_DESC(max_devs, "Specify the maximum number of physical devices. "
|
|
|
"[Default=" __stringify(IPR_DEFAULT_SIS64_DEVS) "]");
|
|
|
module_param_named(number_of_msix, ipr_number_of_msix, int, 0);
|
|
|
MODULE_PARM_DESC(number_of_msix, "Specify the number of MSIX interrupts to use on capable adapters (1 - 16). (default:2)");
|
|
|
+module_param_named(fast_reboot, ipr_fast_reboot, int, S_IRUGO | S_IWUSR);
|
|
|
+MODULE_PARM_DESC(fast_reboot, "Skip adapter shutdown during reboot. Set to 1 to enable. (default: 0)");
|
|
|
MODULE_LICENSE("GPL");
|
|
|
MODULE_VERSION(IPR_DRIVER_VERSION);
|
|
|
|
|
@@ -1462,7 +1465,8 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
|
|
|
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
|
|
|
|
|
|
if (ioasc) {
|
|
|
- if (ioasc != IPR_IOASC_IOA_WAS_RESET)
|
|
|
+ if (ioasc != IPR_IOASC_IOA_WAS_RESET &&
|
|
|
+ ioasc != IPR_IOASC_ABORTED_CMD_TERM_BY_HOST)
|
|
|
dev_err(&ioa_cfg->pdev->dev,
|
|
|
"Host RCB failed with IOASC: 0x%08X\n", ioasc);
|
|
|
|
|
@@ -2566,7 +2570,8 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
|
|
|
ipr_handle_log_data(ioa_cfg, hostrcb);
|
|
|
if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED)
|
|
|
ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV);
|
|
|
- } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {
|
|
|
+ } else if (ioasc != IPR_IOASC_IOA_WAS_RESET &&
|
|
|
+ ioasc != IPR_IOASC_ABORTED_CMD_TERM_BY_HOST) {
|
|
|
dev_err(&ioa_cfg->pdev->dev,
|
|
|
"Host RCB failed with IOASC: 0x%08X\n", ioasc);
|
|
|
}
|
|
@@ -5379,9 +5384,6 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
|
|
|
if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
|
|
|
/* Mask the interrupt */
|
|
|
writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.set_interrupt_mask_reg);
|
|
|
-
|
|
|
- /* Clear the interrupt */
|
|
|
- writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.clr_interrupt_reg);
|
|
|
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
|
|
|
|
|
|
list_del(&ioa_cfg->reset_cmd->queue);
|
|
@@ -8478,6 +8480,122 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
|
|
|
return IPR_RC_JOB_RETURN;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ipr_reset_quiesce_done - Complete IOA disconnect
|
|
|
+ * @ipr_cmd: ipr command struct
|
|
|
+ *
|
|
|
+ * Description: Freeze the adapter to complete quiesce processing
|
|
|
+ *
|
|
|
+ * Return value:
|
|
|
+ * IPR_RC_JOB_CONTINUE
|
|
|
+ **/
|
|
|
+static int ipr_reset_quiesce_done(struct ipr_cmnd *ipr_cmd)
|
|
|
+{
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
|
|
+
|
|
|
+ ENTER;
|
|
|
+ ipr_cmd->job_step = ipr_ioa_bringdown_done;
|
|
|
+ ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
|
|
|
+ LEAVE;
|
|
|
+ return IPR_RC_JOB_CONTINUE;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ipr_reset_cancel_hcam_done - Check for outstanding commands
|
|
|
+ * @ipr_cmd: ipr command struct
|
|
|
+ *
|
|
|
+ * Description: Ensure nothing is outstanding to the IOA and
|
|
|
+ * proceed with IOA disconnect. Otherwise reset the IOA.
|
|
|
+ *
|
|
|
+ * Return value:
|
|
|
+ * IPR_RC_JOB_RETURN / IPR_RC_JOB_CONTINUE
|
|
|
+ **/
|
|
|
+static int ipr_reset_cancel_hcam_done(struct ipr_cmnd *ipr_cmd)
|
|
|
+{
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
|
|
+ struct ipr_cmnd *loop_cmd;
|
|
|
+ struct ipr_hrr_queue *hrrq;
|
|
|
+ int rc = IPR_RC_JOB_CONTINUE;
|
|
|
+ int count = 0;
|
|
|
+
|
|
|
+ ENTER;
|
|
|
+ ipr_cmd->job_step = ipr_reset_quiesce_done;
|
|
|
+
|
|
|
+ for_each_hrrq(hrrq, ioa_cfg) {
|
|
|
+ spin_lock(&hrrq->_lock);
|
|
|
+ list_for_each_entry(loop_cmd, &hrrq->hrrq_pending_q, queue) {
|
|
|
+ count++;
|
|
|
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
|
|
|
+ list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
|
|
|
+ rc = IPR_RC_JOB_RETURN;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ spin_unlock(&hrrq->_lock);
|
|
|
+
|
|
|
+ if (count)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ LEAVE;
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ipr_reset_cancel_hcam - Cancel outstanding HCAMs
|
|
|
+ * @ipr_cmd: ipr command struct
|
|
|
+ *
|
|
|
+ * Description: Cancel any oustanding HCAMs to the IOA.
|
|
|
+ *
|
|
|
+ * Return value:
|
|
|
+ * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
|
|
|
+ **/
|
|
|
+static int ipr_reset_cancel_hcam(struct ipr_cmnd *ipr_cmd)
|
|
|
+{
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
|
|
+ int rc = IPR_RC_JOB_CONTINUE;
|
|
|
+ struct ipr_cmd_pkt *cmd_pkt;
|
|
|
+ struct ipr_cmnd *hcam_cmd;
|
|
|
+ struct ipr_hrr_queue *hrrq = &ioa_cfg->hrrq[IPR_INIT_HRRQ];
|
|
|
+
|
|
|
+ ENTER;
|
|
|
+ ipr_cmd->job_step = ipr_reset_cancel_hcam_done;
|
|
|
+
|
|
|
+ if (!hrrq->ioa_is_dead) {
|
|
|
+ if (!list_empty(&ioa_cfg->hostrcb_pending_q)) {
|
|
|
+ list_for_each_entry(hcam_cmd, &hrrq->hrrq_pending_q, queue) {
|
|
|
+ if (hcam_cmd->ioarcb.cmd_pkt.cdb[0] != IPR_HOST_CONTROLLED_ASYNC)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
|
|
|
+ ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
|
|
|
+ cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
|
|
|
+ cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
|
|
|
+ cmd_pkt->cdb[0] = IPR_CANCEL_REQUEST;
|
|
|
+ cmd_pkt->cdb[1] = IPR_CANCEL_64BIT_IOARCB;
|
|
|
+ cmd_pkt->cdb[10] = ((u64) hcam_cmd->dma_addr >> 56) & 0xff;
|
|
|
+ cmd_pkt->cdb[11] = ((u64) hcam_cmd->dma_addr >> 48) & 0xff;
|
|
|
+ cmd_pkt->cdb[12] = ((u64) hcam_cmd->dma_addr >> 40) & 0xff;
|
|
|
+ cmd_pkt->cdb[13] = ((u64) hcam_cmd->dma_addr >> 32) & 0xff;
|
|
|
+ cmd_pkt->cdb[2] = ((u64) hcam_cmd->dma_addr >> 24) & 0xff;
|
|
|
+ cmd_pkt->cdb[3] = ((u64) hcam_cmd->dma_addr >> 16) & 0xff;
|
|
|
+ cmd_pkt->cdb[4] = ((u64) hcam_cmd->dma_addr >> 8) & 0xff;
|
|
|
+ cmd_pkt->cdb[5] = ((u64) hcam_cmd->dma_addr) & 0xff;
|
|
|
+
|
|
|
+ ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
|
|
|
+ IPR_CANCEL_TIMEOUT);
|
|
|
+
|
|
|
+ rc = IPR_RC_JOB_RETURN;
|
|
|
+ ipr_cmd->job_step = ipr_reset_cancel_hcam;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ ipr_cmd->job_step = ipr_reset_alert;
|
|
|
+
|
|
|
+ LEAVE;
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ipr_reset_ucode_download_done - Microcode download completion
|
|
|
* @ipr_cmd: ipr command struct
|
|
@@ -8560,7 +8678,9 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd)
|
|
|
int rc = IPR_RC_JOB_CONTINUE;
|
|
|
|
|
|
ENTER;
|
|
|
- if (shutdown_type != IPR_SHUTDOWN_NONE &&
|
|
|
+ if (shutdown_type == IPR_SHUTDOWN_QUIESCE)
|
|
|
+ ipr_cmd->job_step = ipr_reset_cancel_hcam;
|
|
|
+ else if (shutdown_type != IPR_SHUTDOWN_NONE &&
|
|
|
!ioa_cfg->hrrq[IPR_INIT_HRRQ].ioa_is_dead) {
|
|
|
ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
|
|
|
ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
|
|
@@ -10035,6 +10155,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
|
|
|
{
|
|
|
struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
|
|
|
unsigned long lock_flags = 0;
|
|
|
+ enum ipr_shutdown_type shutdown_type = IPR_SHUTDOWN_NORMAL;
|
|
|
int i;
|
|
|
|
|
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
|
@@ -10050,9 +10171,31 @@ static void ipr_shutdown(struct pci_dev *pdev)
|
|
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
|
|
}
|
|
|
|
|
|
- ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
|
|
|
+ if (ipr_fast_reboot && system_state == SYSTEM_RESTART && ioa_cfg->sis64)
|
|
|
+ shutdown_type = IPR_SHUTDOWN_QUIESCE;
|
|
|
+
|
|
|
+ ipr_initiate_ioa_bringdown(ioa_cfg, shutdown_type);
|
|
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
|
|
wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
|
|
|
+ if (ipr_fast_reboot && system_state == SYSTEM_RESTART && ioa_cfg->sis64) {
|
|
|
+ if (ioa_cfg->intr_flag == IPR_USE_MSI ||
|
|
|
+ ioa_cfg->intr_flag == IPR_USE_MSIX) {
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < ioa_cfg->nvectors; i++)
|
|
|
+ free_irq(ioa_cfg->vectors_info[i].vec,
|
|
|
+ &ioa_cfg->hrrq[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ioa_cfg->intr_flag == IPR_USE_MSI) {
|
|
|
+ pci_disable_msi(ioa_cfg->pdev);
|
|
|
+ ioa_cfg->intr_flag &= ~IPR_USE_MSI;
|
|
|
+ } else if (ioa_cfg->intr_flag == IPR_USE_MSIX) {
|
|
|
+ pci_disable_msix(ioa_cfg->pdev);
|
|
|
+ ioa_cfg->intr_flag &= ~IPR_USE_MSIX;
|
|
|
+ }
|
|
|
+
|
|
|
+ pci_disable_device(ioa_cfg->pdev);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static struct pci_device_id ipr_pci_table[] = {
|
|
@@ -10210,7 +10353,8 @@ static int ipr_halt(struct notifier_block *nb, ulong event, void *buf)
|
|
|
|
|
|
list_for_each_entry(ioa_cfg, &ipr_ioa_head, queue) {
|
|
|
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
|
|
- if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) {
|
|
|
+ if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds ||
|
|
|
+ (ipr_fast_reboot && event == SYS_RESTART && ioa_cfg->sis64)) {
|
|
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
|
|
continue;
|
|
|
}
|