Re: [PATCH 4/9] scsi_dh: Update hp_sw hardware handler

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

 



I do not have hardware or specs for this device. So, I couldn't review.

On Tue, 2008-06-24 at 12:04 +0200, Hannes Reinecke wrote:
> This patch updates the hp_sw device handler to properly
> check the return codes etc.
> And adds the 'correct' machine definitions.
> 
> Signed-off-by: Hannes Reinecke <hare@xxxxxxx>
> ---
>  drivers/scsi/device_handler/scsi_dh_hp_sw.c |  267 +++++++++++++++++++++++----
>  1 files changed, 231 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
> index 78259bc..c0e00b7 100644
> --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
> +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
> @@ -4,6 +4,7 @@
>   *
>   * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
>   * Copyright (C) 2006 Mike Christie
> + * Copyright (C) 2008 Hannes Reinecke <hare@xxxxxxx>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published by
> @@ -25,13 +26,18 @@
>  #include <scsi/scsi_eh.h>
>  #include <scsi/scsi_dh.h>
> 
> -#define HP_SW_NAME	"hp_sw"
> +#define HP_SW_NAME			"hp_sw"
> 
> -#define HP_SW_TIMEOUT (60 * HZ)
> -#define HP_SW_RETRIES 3
> +#define HP_SW_TIMEOUT			(60 * HZ)
> +#define HP_SW_RETRIES			3
> +
> +#define HP_SW_PATH_UNINITIALIZED	-1
> +#define HP_SW_PATH_ACTIVE		0
> +#define HP_SW_PATH_PASSIVE		1
> 
>  struct hp_sw_dh_data {
>  	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
> +	int path_state;
>  	int retries;
>  };
> 
> @@ -42,51 +48,161 @@ static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
>  	return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
>  }
> 
> -static int hp_sw_done(struct scsi_device *sdev)
> +/*
> + * tur_done - Handle TEST UNIT READY return status
> + * @sdev: sdev the command has been sent to
> + * @errors: blk error code
> + *
> + * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
> + */
> +static int tur_done(struct scsi_device *sdev, unsigned char *sense)
>  {
> -	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
>  	struct scsi_sense_hdr sshdr;
> -	int rc;
> -
> -	sdev_printk(KERN_INFO, sdev, "hp_sw_done\n");
> +	int ret;
> 
> -	rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
> -	if (!rc)
> +	ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
> +	if (!ret) {
> +		sdev_printk(KERN_WARNING, sdev,
> +			    "%s: sending tur failed, no sense available\n",
> +			    HP_SW_NAME);
> +		ret = SCSI_DH_IO;
>  		goto done;
> +	}
>  	switch (sshdr.sense_key) {
> +	case UNIT_ATTENTION:
> +		ret = SCSI_DH_IMM_RETRY;
> +		break;
>  	case NOT_READY:
> -		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
> -			rc = SCSI_DH_RETRY;
> -			h->retries++;
> +		if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
> +			/*
> +			 * LUN not ready - Initialization command required
> +			 *
> +			 * This is the passive path
> +			 */
> +			ret = SCSI_DH_DEV_OFFLINED;
>  			break;
>  		}
> -		/* fall through */
> +		/* Fallthrough */
>  	default:
> -		h->retries++;
> -		rc = SCSI_DH_IMM_RETRY;
> +		sdev_printk(KERN_WARNING, sdev,
> +			   "%s: sending tur failed, sense %x/%x/%x\n",
> +			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
> +			   sshdr.ascq);
> +		break;
>  	}
> 
>  done:
> -	if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
> -		h->retries = 0;
> -	else if (h->retries > HP_SW_RETRIES) {
> -		h->retries = 0;
> +	return ret;
> +}
> +
> +/*
> + * hp_sw_tur - Send TEST UNIT READY
> + * @sdev: sdev command should be sent to
> + *
> + * Use the TEST UNIT READY command to determine
> + * the path state.
> + */
> +static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
> +{
> +	struct request *req;
> +	int ret;
> +
> +	req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
> +	if (!req)
> +		return SCSI_DH_RES_TEMP_UNAVAIL;
> +
> +	req->cmd_type = REQ_TYPE_BLOCK_PC;
> +	req->cmd_flags |= REQ_FAILFAST;
> +	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
> +	memset(req->cmd, 0, MAX_COMMAND_SIZE);
> +	req->cmd[0] = TEST_UNIT_READY;
> +	req->timeout = HP_SW_TIMEOUT;
> +	req->sense = h->sense;
> +	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
> +	req->sense_len = 0;
> +
> +retry:
> +	ret = blk_execute_rq(req->q, NULL, req, 1);
> +	if (ret == -EIO) {
> +		if (req->sense_len > 0) {
> +			ret = tur_done(sdev, h->sense);
> +		} else {
> +			sdev_printk(KERN_WARNING, sdev,
> +				    "%s: sending tur failed with %x\n",
> +				    HP_SW_NAME, req->errors);
> +			ret = SCSI_DH_IO;
> +		}
> +	} else {
> +		h->path_state = HP_SW_PATH_ACTIVE;
> +		ret = SCSI_DH_OK;
> +	}
> +	if (ret == SCSI_DH_IMM_RETRY)
> +		goto retry;
> +	if (ret == SCSI_DH_DEV_OFFLINED) {
> +		h->path_state = HP_SW_PATH_PASSIVE;
> +		ret = SCSI_DH_OK;
> +	}
> +
> +	blk_put_request(req);
> +
> +	return ret;
> +}
> +
> +/*
> + * start_done - Handle START STOP UNIT return status
> + * @sdev: sdev the command has been sent to
> + * @errors: blk error code
> + */
> +static int start_done(struct scsi_device *sdev, unsigned char *sense)
> +{
> +	struct scsi_sense_hdr sshdr;
> +	int rc;
> +
> +	rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
> +	if (!rc) {
> +		sdev_printk(KERN_WARNING, sdev,
> +			    "%s: sending start_stop_unit failed, "
> +			    "no sense available\n",
> +			    HP_SW_NAME);
> +		return SCSI_DH_IO;
> +	}
> +	switch (sshdr.sense_key) {
> +	case NOT_READY:
> +		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
> +			/*
> +			 * LUN not ready - manual intervention required
> +			 *
> +			 * Switch-over in progress, retry.
> +			 */
> +			rc = SCSI_DH_RETRY;
> +			break;
> +		}
> +		/* fall through */
> +	default:
> +		sdev_printk(KERN_WARNING, sdev,
> +			   "%s: sending start_stop_unit failed, sense %x/%x/%x\n",
> +			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
> +			   sshdr.ascq);
>  		rc = SCSI_DH_IO;
>  	}
> +
>  	return rc;
>  }
> 
> -static int hp_sw_activate(struct scsi_device *sdev)
> +/*
> + * hp_sw_start_stop - Send START STOP UNIT command
> + * @sdev: sdev command should be sent to
> + *
> + * Sending START STOP UNIT activates the SP.
> + */
> +static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
>  {
> -	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
>  	struct request *req;
> -	int ret = SCSI_DH_RES_TEMP_UNAVAIL;
> +	int ret, retry;
> 
>  	req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
>  	if (!req)
> -		goto done;
> -
> -	sdev_printk(KERN_INFO, sdev, "sending START_STOP.");
> +		return SCSI_DH_RES_TEMP_UNAVAIL;
> 
>  	req->cmd_type = REQ_TYPE_BLOCK_PC;
>  	req->cmd_flags |= REQ_FAILFAST;
> @@ -98,19 +214,78 @@ static int hp_sw_activate(struct scsi_device *sdev)
>  	req->sense = h->sense;
>  	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
>  	req->sense_len = 0;
> +	retry = h->retries;
> 
> +retry:
>  	ret = blk_execute_rq(req->q, NULL, req, 1);
> -	if (!ret) /* SUCCESS */
> -		ret = hp_sw_done(sdev);
> -	else
> +	if (ret == -EIO) {
> +		if (req->sense_len > 0) {
> +			ret = start_done(sdev, h->sense);
> +		} else {
> +			sdev_printk(KERN_WARNING, sdev,
> +				    "%s: sending start_stop_unit failed with %x\n",
> +				    HP_SW_NAME, req->errors);
> +			ret = SCSI_DH_IO;
> +		}
> +	} else
> +		ret = SCSI_DH_OK;
> +
> +	if (ret == SCSI_DH_RETRY) {
> +		if (--retry)
> +			goto retry;
>  		ret = SCSI_DH_IO;
> -done:
> +	}
> +
> +	blk_put_request(req);
> +
> +	return ret;
> +}
> +
> +static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
> +{
> +	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
> +	int ret = BLKPREP_OK;
> +
> +	if (h->path_state != HP_SW_PATH_ACTIVE) {
> +		ret = BLKPREP_KILL;
> +		req->cmd_flags |= REQ_QUIET;
> +	}
> +	return ret;
> +
> +}
> +
> +/*
> + * hp_sw_activate - Activate a path
> + * @sdev: sdev on the path to be activated
> + *
> + * The HP Active/Passive firmware is pretty simple;
> + * the passive path reports NOT READY with sense codes
> + * 0x04/0x02; a START STOP UNIT command will then
> + * activate the passive path (and deactivate the
> + * previously active one).
> + */
> +static int hp_sw_activate(struct scsi_device *sdev)
> +{
> +	int ret = SCSI_DH_OK;
> +	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
> +
> +	ret = hp_sw_tur(sdev, h);
> +
> +	if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
> +		ret = hp_sw_start_stop(sdev, h);
> +		if (ret == SCSI_DH_OK)
> +			sdev_printk(KERN_INFO, sdev,
> +				    "%s: activated path\n",
> +				    HP_SW_NAME);
> +	}
> +
>  	return ret;
>  }
> 
>  const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
> -	{"COMPAQ", "MSA"},
> -	{"HP", "HSV"},
> +	{"COMPAQ", "MSA1000 VOLUME"},
> +	{"COMPAQ", "HSV110"},
> +	{"HP", "HSV100"},
>  	{"DEC", "HSG80"},
>  	{NULL, NULL},
>  };
> @@ -125,30 +300,50 @@ static struct scsi_device_handler hp_sw_dh = {
>  	.attach		= hp_sw_bus_attach,
>  	.detach		= hp_sw_bus_detach,
>  	.activate	= hp_sw_activate,
> +	.prep_fn	= hp_sw_prep_fn,
>  };
> 
>  static int hp_sw_bus_attach(struct scsi_device *sdev)
>  {
>  	struct scsi_dh_data *scsi_dh_data;
> +	struct hp_sw_dh_data *h;
>  	unsigned long flags;
> +	int ret;
> 
>  	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
>  			       + sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
>  	if (!scsi_dh_data) {
> -		sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
> +		sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
>  			    HP_SW_NAME);
>  		return 0;
>  	}
> 
>  	scsi_dh_data->scsi_dh = &hp_sw_dh;
> +	h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
> +	h->path_state = HP_SW_PATH_UNINITIALIZED;
> +	h->retries = HP_SW_RETRIES;
> +
> +	ret = hp_sw_tur(sdev, h);
> +	if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
> +		goto failed;
> +
>  	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
>  	sdev->scsi_dh_data = scsi_dh_data;
>  	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
> +
>  	try_module_get(THIS_MODULE);
> 
> -	sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
> +	sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
> +		    HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
> +		    "active":"passive");
> 
>  	return 0;
> +
> +failed:
> +	kfree(scsi_dh_data);
> +	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
> +		    HP_SW_NAME);
> +	return -EINVAL;
>  }
> 
>  static void hp_sw_bus_detach( struct scsi_device *sdev )
> @@ -162,7 +357,7 @@ static void hp_sw_bus_detach( struct scsi_device *sdev )
>  	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
>  	module_put(THIS_MODULE);
> 
> -	sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", HP_SW_NAME);
> +	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
> 
>  	kfree(scsi_dh_data);
>  }
> @@ -180,6 +375,6 @@ static void __exit hp_sw_exit(void)
>  module_init(hp_sw_init);
>  module_exit(hp_sw_exit);
> 
> -MODULE_DESCRIPTION("HP MSA 1000");
> +MODULE_DESCRIPTION("HP Active/Passive driver");
>  MODULE_AUTHOR("Mike Christie <michaelc@xxxxxxxxxxx");
>  MODULE_LICENSE("GPL");

--
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