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

[dm-devel] [PATCH 5/5] scsi_dh: Update hp_sw hardware handler



This patch updates the hp_sw device handler to properly
check the return codes etc.
And we now even free up the request ...

Signed-off-by: Hannes Reinecke <hare suse de>
---
 drivers/scsi/device_handler/scsi_dh_hp_sw.c |  212 +++++++++++++++++++++++---
 1 files changed, 187 insertions(+), 25 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index d5d7906..a44b319 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -25,13 +25,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,41 +47,137 @@ 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)
+static int tur_done(struct scsi_device *sdev, int errors)
+{
+	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+	struct scsi_sense_hdr sshdr;
+	int ret;
+
+	if (status_byte(errors) != CHECK_CONDITION) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: sending tur failed with %x\n",
+			    HP_SW_NAME, errors);
+		ret = SCSI_DH_IO;
+		goto done;
+	}
+	ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
+	if (!ret) {
+		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 == 2)) {
+			/*
+			 * LUN not ready - Initialization command required
+			 *
+			 * This is the passive path
+			 */
+			h->path_state = HP_SW_PATH_PASSIVE;
+			ret = SCSI_DH_OK;
+			break;
+		}
+		/* Fallthrough */
+	default:
+		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:
+	return ret;
+}
+
+static int hp_sw_tur(struct scsi_device *sdev)
+{
+	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+	struct request *req;
+	int ret = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
+	if (!req)
+		goto done;
+
+	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) {
+		ret = tur_done(sdev, req->errors);
+	} else {
+		h->path_state = HP_SW_PATH_ACTIVE;
+		ret = SCSI_DH_OK;
+	}
+	if (ret == SCSI_DH_IMM_RETRY)
+		goto retry;
+
+	blk_put_request(req);
+
+done:
+	return ret;
+}
+
+static int start_done(struct scsi_device *sdev, int errors)
 {
 	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");
+	if (status_byte(errors) != CHECK_CONDITION) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: sending start_stop_unit failed with %x\n",
+			    HP_SW_NAME, errors);
+		rc = SCSI_DH_IO;
+		goto done;
+	}
 
 	rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
-	if (!rc)
+	if (!rc) {
+		rc = SCSI_DH_IO;
 		goto done;
+	}
 	switch (sshdr.sense_key) {
 	case NOT_READY:
-		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
+		if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
+			/*
+			 * LUN not ready - initialization command required
+			 *
+			 * Switch-over in progress, retry.
+			 */
 			rc = SCSI_DH_RETRY;
-			h->retries++;
+			h->retries--;
 			break;
 		}
 		/* fall through */
 	default:
-		h->retries++;
-		rc = SCSI_DH_IMM_RETRY;
+		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);
+		h->retries--;
+		rc = SCSI_DH_RETRY;
 	}
+	if (rc == SCSI_DH_RETRY && !h->retries)
+		rc = SCSI_DH_IO;
 
 done:
-	if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
-		h->retries = 0;
-	else if (h->retries > HP_SW_RETRIES) {
-		h->retries = 0;
-		rc = SCSI_DH_IO;
-	}
 	return rc;
 }
 
-static int hp_sw_activate(struct scsi_device *sdev)
+static int hp_sw_start_stop(struct scsi_device *sdev)
 {
 	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
 	struct request *req;
@@ -86,8 +187,6 @@ static int hp_sw_activate(struct scsi_device *sdev)
 	if (!req)
 		goto done;
 
-	sdev_printk(KERN_INFO, sdev, "sending START_STOP.");
-
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_flags |= REQ_FAILFAST;
 	req->cmd_len = COMMAND_SIZE(START_STOP);
@@ -99,17 +198,55 @@ static int hp_sw_activate(struct scsi_device *sdev)
 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
 	req->sense_len = 0;
 
+retry:
 	ret = blk_execute_rq(req->q, NULL, req, 1);
-	if (!ret) /* SUCCESS */
-		ret = hp_sw_done(sdev);
+	if (ret == -EIO)
+		ret = start_done(sdev, req->errors);
 	else
 		ret = SCSI_DH_IO;
+
+	if (ret == SCSI_DH_RETRY)
+		goto retry;
+
+	blk_put_request(req);
 done:
 	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;
+
+}
+
+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);
+
+	if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
+		ret = hp_sw_start_stop(sdev);
+		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"},
+	{"COMPAQ", "MSA1000"},
+	{"COMPAQ", "HSV110"},
 	{"HP", "HSV100"},
 	{"DEC", "HSG80"},
 	{NULL, NULL},
@@ -125,30 +262,55 @@ 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;
 	}
 
+	h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
+	h->path_state = HP_SW_PATH_UNINITIALIZED;
+	h->retries = HP_SW_RETRIES;
+
 	scsi_dh_data->scsi_dh = &hp_sw_dh;
 	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);
+
+	ret = hp_sw_tur(sdev);
+	if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
+		goto failed;
+
+	sdev_printk(KERN_INFO, sdev, "%s: %s path\n",
+		    HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
+		    "active":"passive");
+
 	try_module_get(THIS_MODULE);
 
-	sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
+	sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", HP_SW_NAME);
 
 	return 0;
+
+failed:
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	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 )
@@ -166,7 +328,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);
 }
-- 
1.5.2.4


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