[PATCH RESEND 3/5] ipr: Kexec boot speed improvements

wenxiong at linux.vnet.ibm.com wenxiong at linux.vnet.ibm.com
Tue Dec 2 13:24:44 PST 2014


Reviewed-by: Wen Xiong<wenxiong at linux.vnet.ibm.com>

Thanks,
Wendy

Quoting Brian King <brking at linux.vnet.ibm.com>:

> Currently when performing a kexec boot with an ipr adapter,
> the adapter gets shutdown completely, flushing all write
> cache, as well as performing a full hardware reset of the card
> during the shutdown phase of the old kernel. This forces
> the new kernel to then wait for the adapter firmware to
> reinitialize, which slows down kexec boot. There is no
> need to do all of this on the newer ipr adapters, since they
> support the ability to cancel outstanding error buffers.
>
> This patch adds a special case for kexec boot to simply
> cancel these outstanding error buffers, and as long as
> there is no other I/O outstanding to the adapter, which
> there shouldn't be, place the adapter into a state
> where it has no memory of any DMA addresses from the old
> kernel, then disable the device. This significantly
> speeds up kexec boot, particularly in configurations with
> multiple ipr adapters.
>
> Cc: Eric Biederman <ebiederm at xmission.com>
> Cc: kexec <kexec at lists.infradead.org>
> Tested-by: Anton Blanchard <anton at samba.org>
> Signed-off-by: Brian King <brking at linux.vnet.ibm.com>
> ---
>
>  drivers/scsi/ipr.c |  158  
> ++++++++++++++++++++++++++++++++++++++++++++++++++---
>  drivers/scsi/ipr.h |    6 +-
>  2 files changed, 155 insertions(+), 9 deletions(-)
>
> diff -puN drivers/scsi/ipr.h~ipr_cancel_hcams2 drivers/scsi/ipr.h
> --- scsi-queue/drivers/scsi/ipr.h~ipr_cancel_hcams2	2014-12-02  
> 12:24:48.848443248 -0600
> +++ scsi-queue-bjking1/drivers/scsi/ipr.h	2014-12-02 12:46:09.574668020 -0600
> @@ -196,6 +196,8 @@
>  /*
>   * Adapter Commands
>   */
> +#define IPR_CANCEL_REQUEST				0xC0
> +#define	IPR_CANCEL_64BIT_IOARCB			0x01
>  #define IPR_QUERY_RSRC_STATE				0xC2
>  #define IPR_RESET_DEVICE				0xC3
>  #define	IPR_RESET_TYPE_SELECT				0x80
> @@ -222,6 +224,7 @@
>  #define IPR_ABBREV_SHUTDOWN_TIMEOUT		(10 * HZ)
>  #define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO	(2 * 60 * HZ)
>  #define IPR_DEVICE_RESET_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
> +#define IPR_CANCEL_TIMEOUT			(ipr_fastfail ? 10 * HZ : 30 * HZ)
>  #define IPR_CANCEL_ALL_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
>  #define IPR_ABORT_TASK_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
>  #define IPR_INTERNAL_TIMEOUT			(ipr_fastfail ? 10 * HZ : 30 * HZ)
> @@ -1402,7 +1405,8 @@ enum ipr_shutdown_type {
>  	IPR_SHUTDOWN_NORMAL = 0x00,
>  	IPR_SHUTDOWN_PREPARE_FOR_NORMAL = 0x40,
>  	IPR_SHUTDOWN_ABBREV = 0x80,
> -	IPR_SHUTDOWN_NONE = 0x100
> +	IPR_SHUTDOWN_NONE = 0x100,
> +	IPR_SHUTDOWN_KEXEC = 0x101,
>  };
>
>  struct ipr_trace_entry {
> diff -puN drivers/scsi/ipr.c~ipr_cancel_hcams2 drivers/scsi/ipr.c
> --- scsi-queue/drivers/scsi/ipr.c~ipr_cancel_hcams2	2014-12-02  
> 12:24:48.851443224 -0600
> +++ scsi-queue-bjking1/drivers/scsi/ipr.c	2014-12-02 12:46:09.705666926 -0600
> @@ -76,6 +76,7 @@
>  #include <linux/hdreg.h>
>  #include <linux/reboot.h>
>  #include <linux/stringify.h>
> +#include <linux/kexec.h>
>  #include <asm/io.h>
>  #include <asm/irq.h>
>  #include <asm/processor.h>
> @@ -1459,7 +1460,8 @@ static void ipr_process_ccn(struct ipr_c
>  	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);
>
> @@ -2563,7 +2565,8 @@ static void ipr_process_error(struct ipr
>  		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);
>  	}
> @@ -5310,9 +5313,6 @@ static irqreturn_t ipr_handle_other_inte
>  	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);
> @@ -8411,6 +8411,122 @@ static int ipr_reset_alert(struct ipr_cm
>  }
>
>  /**
> + * ipr_reset_kexec_done - Complete IOA disconnect
> + * @ipr_cmd:	ipr command struct
> + *
> + * Description: Freeze the adapter to complete kexec processing
> + *
> + * Return value:
> + * 	IPR_RC_JOB_CONTINUE
> + **/
> +static int ipr_reset_kexec_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_kexec_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
>   *
> @@ -8492,7 +8608,9 @@ static int ipr_reset_shutdown_ioa(struct
>  	int rc = IPR_RC_JOB_CONTINUE;
>
>  	ENTER;
> -	if (shutdown_type != IPR_SHUTDOWN_NONE &&
> +	if (shutdown_type == IPR_SHUTDOWN_KEXEC)
> +		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;
> @@ -9967,6 +10085,7 @@ static void ipr_shutdown(struct pci_dev
>  {
>  	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);
> @@ -9982,9 +10101,31 @@ static void ipr_shutdown(struct pci_dev
>  		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
>  	}
>
> -	ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
> +	if (kexec_in_progress && ioa_cfg->sis64)
> +		shutdown_type = IPR_SHUTDOWN_KEXEC;
> +
> +	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 (kexec_in_progress && 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[] = {
> @@ -10142,7 +10283,8 @@ static int ipr_halt(struct notifier_bloc
>
>  	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 ||
> +		    (kexec_in_progress && ioa_cfg->sis64)) {
>  			spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
>  			continue;
>  		}
> _





More information about the kexec mailing list