Re: [PATCH 19/35] hpsa: add task management for ioaccel mode 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 02/18/2014 08:56 PM, Stephen M. Cameron wrote:
> From: Scott Teel <scott.teel@xxxxxx>
>
> Underlying firmware cannot handle task abort on accelerated path (SSD Smart Path).
> Change abort requests for accelerated path commands to physical target reset.
> Send reset request on normal IO path.
>
> Signed-off-by: Scott Teel <scott.teel@xxxxxx>
> Signed-off-by: Mike Miller <michael.miller@xxxxxxxxxxxxx>
> Acked-by: Stephen M. Cameron <scameron@xxxxxxxxxxxxxxxxxx>
> ---
>  drivers/scsi/hpsa.c     |  166 ++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/scsi/hpsa_cmd.h |    7 +-
>  2 files changed, 167 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
> index 021d077..8880f54 100644
> --- a/drivers/scsi/hpsa.c
> +++ b/drivers/scsi/hpsa.c
> @@ -2307,6 +2307,85 @@ static int add_ext_target_dev(struct ctlr_info *h,
>  }
>  
>  /*
> + * Get address of physical disk used for an ioaccel2 mode command:
> + *	1. Extract ioaccel2 handle from the command.
> + *	2. Find a matching ioaccel2 handle from list of physical disks.
> + *	3. Return:
> + *		1 and set scsi3addr to address of matching physical
> + *		0 if no matching physical disk was found.
> + */
> +static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
> +	struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr)
> +{
> +	struct ReportExtendedLUNdata *physicals = NULL;
> +	int responsesize = 24;	/* size of physical extended response */
> +	int extended = 2;	/* flag forces reporting 'other dev info'. */
> +	int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize;
> +	u32 nphysicals = 0;	/* number of reported physical devs */
> +	int found = 0;		/* found match (1) or not (0) */
> +	u32 find;		/* handle we need to match */
> +	int i;
> +	struct scsi_cmnd *scmd;	/* scsi command within request being aborted */
> +	struct hpsa_scsi_dev_t *d; /* device of request being aborted */
> +	struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */
> +	u32 it_nexus;		/* 4 byte device handle for the ioaccel2 cmd */
> +	u32 scsi_nexus;		/* 4 byte device handle for the ioaccel2 cmd */
> +
> +	if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2)
> +		return 0; /* no match */
> +
> +	/* point to the ioaccel2 device handle */
> +	c2a = &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex];
> +	if (c2a == NULL)
> +		return 0; /* no match */
> +
> +	scmd = (struct scsi_cmnd *) ioaccel2_cmd_to_abort->scsi_cmd;
> +	if (scmd == NULL)
> +		return 0; /* no match */
> +
> +	d = scmd->device->hostdata;
> +	if (d == NULL)
> +		return 0; /* no match */
> +
> +	it_nexus = cpu_to_le32((u32) d->ioaccel_handle);
> +	scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus);
> +	find = c2a->scsi_nexus;
> +
> +	/* Get the list of physical devices */
> +	physicals = kzalloc(reportsize, GFP_KERNEL);

Hi, please add a test for physicals != NULL
Tomas 

> +	if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
> +		reportsize, extended)) {
> +		dev_err(&h->pdev->dev,
> +			"Can't lookup %s device handle: report physical LUNs failed.\n",
> +			"HP SSD Smart Path");
> +		kfree(physicals);
> +		return 0;
> +	}
> +	nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) /
> +							responsesize;
> +
> +
> +	/* find ioaccel2 handle in list of physicals: */
> +	for (i = 0; i < nphysicals; i++) {
> +		/* handle is in bytes 28-31 of each lun */
> +		if (memcmp(&((struct ReportExtendedLUNdata *)
> +				physicals)->LUN[i][20], &find, 4) != 0) {
> +			continue; /* didn't match */
> +		}
> +		found = 1;
> +		memcpy(scsi3addr, &((struct ReportExtendedLUNdata *)
> +					physicals)->LUN[i][0], 8);
> +		break; /* found it */
> +	}
> +
> +	kfree(physicals);
> +	if (found)
> +		return 1;
> +	else
> +		return 0;
> +
> +}
> +/*
>   * Do CISS_REPORT_PHYS and CISS_REPORT_LOG.  Data is returned in physdev,
>   * logdev.  The number of luns in physdev and logdev are returned in
>   * *nphysicals and *nlogicals, respectively.
> @@ -3423,12 +3502,20 @@ static void hpsa_get_tag(struct ctlr_info *h,
>  			&h->ioaccel_cmd_pool[c->cmdindex];
>  		*tagupper = cm1->Tag.upper;
>  		*taglower = cm1->Tag.lower;
> -	} else {
> -		*tagupper = c->Header.Tag.upper;
> -		*taglower = c->Header.Tag.lower;
> +		return;
> +	}
> +	if (c->cmd_type == CMD_IOACCEL2) {
> +		struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
> +			&h->ioaccel2_cmd_pool[c->cmdindex];
> +		*tagupper = cm2->Tag.upper;
> +		*taglower = cm2->Tag.lower;
> +		return;
>  	}
> +	*tagupper = c->Header.Tag.upper;
> +	*taglower = c->Header.Tag.lower;
>  }
>  
> +
>  static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
>  	struct CommandList *abort, int swizzle)
>  {
> @@ -3524,6 +3611,71 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
>  	return NULL;
>  }
>  
> +/* ioaccel2 path firmware cannot handle abort task requests.
> + * Change abort requests to physical target reset, and send to the
> + * address of the physical disk used for the ioaccel 2 command.
> + * Return 0 on success (IO_OK)
> + *	 -1 on failure
> + */
> +
> +static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
> +	unsigned char *scsi3addr, struct CommandList *abort)
> +{
> +	int rc = IO_OK;
> +	struct scsi_cmnd *scmd; /* scsi command within request being aborted */
> +	struct hpsa_scsi_dev_t *dev; /* device to which scsi cmd was sent */
> +	unsigned char phys_scsi3addr[8]; /* addr of phys disk with volume */
> +	unsigned char *psa = &phys_scsi3addr[0];
> +
> +	/* Get a pointer to the hpsa logical device. */
> +	scmd = (struct scsi_cmnd *) abort->scsi_cmd;
> +	dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
> +	if (dev == NULL) {
> +		dev_warn(&h->pdev->dev,
> +			"Cannot abort: no device pointer for command.\n");
> +			return -1; /* not abortable */
> +	}
> +
> +	if (!dev->offload_enabled) {
> +		dev_warn(&h->pdev->dev,
> +			"Can't abort: device is not operating in HP SSD Smart Path mode.\n");
> +		return -1; /* not abortable */
> +	}
> +
> +	/* Incoming scsi3addr is logical addr. We need physical disk addr. */
> +	if (!hpsa_get_pdisk_of_ioaccel2(h, abort, psa)) {
> +		dev_warn(&h->pdev->dev, "Can't abort: Failed lookup of physical address.\n");
> +		return -1; /* not abortable */
> +	}
> +
> +	/* send the reset */
> +	rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET);
> +	if (rc != 0) {
> +		dev_warn(&h->pdev->dev,
> +			"Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> +			psa[0], psa[1], psa[2], psa[3],
> +			psa[4], psa[5], psa[6], psa[7]);
> +		return rc; /* failed to reset */
> +	}
> +
> +	/* wait for device to recover */
> +	if (wait_for_device_to_become_ready(h, psa) != 0) {
> +		dev_warn(&h->pdev->dev,
> +			"Reset as abort: Failed: Device never recovered from reset: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> +			psa[0], psa[1], psa[2], psa[3],
> +			psa[4], psa[5], psa[6], psa[7]);
> +		return -1;  /* failed to recover */
> +	}
> +
> +	/* device recovered */
> +	dev_info(&h->pdev->dev,
> +		"Reset as abort: Device recovered from reset: scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
> +		psa[0], psa[1], psa[2], psa[3],
> +		psa[4], psa[5], psa[6], psa[7]);
> +
> +	return rc; /* success */
> +}
> +
>  /* Some Smart Arrays need the abort tag swizzled, and some don't.  It's hard to
>   * tell which kind we're dealing with, so we send the abort both ways.  There
>   * shouldn't be any collisions between swizzled and unswizzled tags due to the
> @@ -3537,6 +3689,14 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
>  	struct CommandList *c;
>  	int rc = 0, rc2 = 0;
>  
> +	/* ioccelerator mode 2 commands should be aborted via the
> +	 * accelerated path, since RAID path is unaware of these commands,
> +	 * but underlying firmware can't handle abort TMF.
> +	 * Change abort to physical device reset.
> +	 */
> +	if (abort->cmd_type == CMD_IOACCEL2)
> +		return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort);
> +
>  	/* we do not expect to find the swizzled tag in our queue, but
>  	 * check anyway just to be sure the assumptions which make this
>  	 * the case haven't become wrong.
> diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
> index f6430b4..e048167 100644
> --- a/drivers/scsi/hpsa_cmd.h
> +++ b/drivers/scsi/hpsa_cmd.h
> @@ -82,8 +82,9 @@
>  #define ATTR_ACA                0x07
>  
>  /* cdb type */
> -#define TYPE_CMD				0x00
> -#define TYPE_MSG				0x01
> +#define TYPE_CMD		0x00
> +#define TYPE_MSG		0x01
> +#define TYPE_IOACCEL2_CMD	0x81 /* 0x81 is not used by hardware */
>  
>  /* Message Types  */
>  #define HPSA_TASK_MANAGEMENT    0x00
> @@ -525,7 +526,7 @@ struct io_accel2_cmd {
>   * FIXME: this can't be all I need mfm
>   */
>  #define IOACCEL2_IU_TYPE	0x40
> -#define IU_TYPE_TMF		0x41
> +#define IOACCEL2_IU_TMF_TYPE	0x41
>  #define IOACCEL2_DIR_NO_DATA	0x00
>  #define IOACCEL2_DIR_DATA_IN	0x01
>  #define IOACCEL2_DIR_DATA_OUT	0x02
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux