[SCSI] scsi_dh: Update hp_sw hardware handler

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@suse.de>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Hannes Reinecke and committed by
James Bottomley
2aef6d5c b6ff1b14

+234 -38
+234 -38
drivers/scsi/device_handler/scsi_dh_hp_sw.c
··· 4 4 * 5 5 * Copyright (C) 2006 Red Hat, Inc. All rights reserved. 6 6 * Copyright (C) 2006 Mike Christie 7 + * Copyright (C) 2008 Hannes Reinecke <hare@suse.de> 7 8 * 8 9 * This program is free software; you can redistribute it and/or modify 9 10 * it under the terms of the GNU General Public License as published by ··· 26 25 #include <scsi/scsi_eh.h> 27 26 #include <scsi/scsi_dh.h> 28 27 29 - #define HP_SW_NAME "hp_sw" 28 + #define HP_SW_NAME "hp_sw" 30 29 31 - #define HP_SW_TIMEOUT (60 * HZ) 32 - #define HP_SW_RETRIES 3 30 + #define HP_SW_TIMEOUT (60 * HZ) 31 + #define HP_SW_RETRIES 3 32 + 33 + #define HP_SW_PATH_UNINITIALIZED -1 34 + #define HP_SW_PATH_ACTIVE 0 35 + #define HP_SW_PATH_PASSIVE 1 33 36 34 37 struct hp_sw_dh_data { 35 38 unsigned char sense[SCSI_SENSE_BUFFERSIZE]; 39 + int path_state; 36 40 int retries; 37 41 }; 38 42 ··· 48 42 return ((struct hp_sw_dh_data *) scsi_dh_data->buf); 49 43 } 50 44 51 - static int hp_sw_done(struct scsi_device *sdev) 45 + /* 46 + * tur_done - Handle TEST UNIT READY return status 47 + * @sdev: sdev the command has been sent to 48 + * @errors: blk error code 49 + * 50 + * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path 51 + */ 52 + static int tur_done(struct scsi_device *sdev, unsigned char *sense) 52 53 { 53 - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); 54 + struct scsi_sense_hdr sshdr; 55 + int ret; 56 + 57 + ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); 58 + if (!ret) { 59 + sdev_printk(KERN_WARNING, sdev, 60 + "%s: sending tur failed, no sense available\n", 61 + HP_SW_NAME); 62 + ret = SCSI_DH_IO; 63 + goto done; 64 + } 65 + switch (sshdr.sense_key) { 66 + case UNIT_ATTENTION: 67 + ret = SCSI_DH_IMM_RETRY; 68 + break; 69 + case NOT_READY: 70 + if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) { 71 + /* 72 + * LUN not ready - Initialization command required 73 + * 74 + * This is the passive path 75 + */ 76 + ret = SCSI_DH_DEV_OFFLINED; 77 + break; 78 + } 79 + /* Fallthrough */ 80 + default: 81 + sdev_printk(KERN_WARNING, sdev, 82 + "%s: sending tur failed, sense %x/%x/%x\n", 83 + HP_SW_NAME, sshdr.sense_key, sshdr.asc, 84 + sshdr.ascq); 85 + break; 86 + } 87 + 88 + done: 89 + return ret; 90 + } 91 + 92 + /* 93 + * hp_sw_tur - Send TEST UNIT READY 94 + * @sdev: sdev command should be sent to 95 + * 96 + * Use the TEST UNIT READY command to determine 97 + * the path state. 98 + */ 99 + static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) 100 + { 101 + struct request *req; 102 + int ret; 103 + 104 + req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); 105 + if (!req) 106 + return SCSI_DH_RES_TEMP_UNAVAIL; 107 + 108 + req->cmd_type = REQ_TYPE_BLOCK_PC; 109 + req->cmd_flags |= REQ_FAILFAST; 110 + req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); 111 + memset(req->cmd, 0, MAX_COMMAND_SIZE); 112 + req->cmd[0] = TEST_UNIT_READY; 113 + req->timeout = HP_SW_TIMEOUT; 114 + req->sense = h->sense; 115 + memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); 116 + req->sense_len = 0; 117 + 118 + retry: 119 + ret = blk_execute_rq(req->q, NULL, req, 1); 120 + if (ret == -EIO) { 121 + if (req->sense_len > 0) { 122 + ret = tur_done(sdev, h->sense); 123 + } else { 124 + sdev_printk(KERN_WARNING, sdev, 125 + "%s: sending tur failed with %x\n", 126 + HP_SW_NAME, req->errors); 127 + ret = SCSI_DH_IO; 128 + } 129 + } else { 130 + h->path_state = HP_SW_PATH_ACTIVE; 131 + ret = SCSI_DH_OK; 132 + } 133 + if (ret == SCSI_DH_IMM_RETRY) 134 + goto retry; 135 + if (ret == SCSI_DH_DEV_OFFLINED) { 136 + h->path_state = HP_SW_PATH_PASSIVE; 137 + ret = SCSI_DH_OK; 138 + } 139 + 140 + blk_put_request(req); 141 + 142 + return ret; 143 + } 144 + 145 + /* 146 + * start_done - Handle START STOP UNIT return status 147 + * @sdev: sdev the command has been sent to 148 + * @errors: blk error code 149 + */ 150 + static int start_done(struct scsi_device *sdev, unsigned char *sense) 151 + { 54 152 struct scsi_sense_hdr sshdr; 55 153 int rc; 56 154 57 - sdev_printk(KERN_INFO, sdev, "hp_sw_done\n"); 58 - 59 - rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); 60 - if (!rc) 61 - goto done; 155 + rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); 156 + if (!rc) { 157 + sdev_printk(KERN_WARNING, sdev, 158 + "%s: sending start_stop_unit failed, " 159 + "no sense available\n", 160 + HP_SW_NAME); 161 + return SCSI_DH_IO; 162 + } 62 163 switch (sshdr.sense_key) { 63 164 case NOT_READY: 64 165 if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { 166 + /* 167 + * LUN not ready - manual intervention required 168 + * 169 + * Switch-over in progress, retry. 170 + */ 65 171 rc = SCSI_DH_RETRY; 66 - h->retries++; 67 172 break; 68 173 } 69 174 /* fall through */ 70 175 default: 71 - h->retries++; 72 - rc = SCSI_DH_IMM_RETRY; 73 - } 74 - 75 - done: 76 - if (rc == SCSI_DH_OK || rc == SCSI_DH_IO) 77 - h->retries = 0; 78 - else if (h->retries > HP_SW_RETRIES) { 79 - h->retries = 0; 176 + sdev_printk(KERN_WARNING, sdev, 177 + "%s: sending start_stop_unit failed, sense %x/%x/%x\n", 178 + HP_SW_NAME, sshdr.sense_key, sshdr.asc, 179 + sshdr.ascq); 80 180 rc = SCSI_DH_IO; 81 181 } 182 + 82 183 return rc; 83 184 } 84 185 85 - static int hp_sw_activate(struct scsi_device *sdev) 186 + /* 187 + * hp_sw_start_stop - Send START STOP UNIT command 188 + * @sdev: sdev command should be sent to 189 + * 190 + * Sending START STOP UNIT activates the SP. 191 + */ 192 + static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h) 86 193 { 87 - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); 88 194 struct request *req; 89 - int ret = SCSI_DH_RES_TEMP_UNAVAIL; 195 + int ret, retry; 90 196 91 - req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC); 197 + req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); 92 198 if (!req) 93 - goto done; 94 - 95 - sdev_printk(KERN_INFO, sdev, "sending START_STOP."); 199 + return SCSI_DH_RES_TEMP_UNAVAIL; 96 200 97 201 req->cmd_type = REQ_TYPE_BLOCK_PC; 98 202 req->cmd_flags |= REQ_FAILFAST; ··· 214 98 req->sense = h->sense; 215 99 memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); 216 100 req->sense_len = 0; 101 + retry = h->retries; 217 102 103 + retry: 218 104 ret = blk_execute_rq(req->q, NULL, req, 1); 219 - if (!ret) /* SUCCESS */ 220 - ret = hp_sw_done(sdev); 221 - else 105 + if (ret == -EIO) { 106 + if (req->sense_len > 0) { 107 + ret = start_done(sdev, h->sense); 108 + } else { 109 + sdev_printk(KERN_WARNING, sdev, 110 + "%s: sending start_stop_unit failed with %x\n", 111 + HP_SW_NAME, req->errors); 112 + ret = SCSI_DH_IO; 113 + } 114 + } else 115 + ret = SCSI_DH_OK; 116 + 117 + if (ret == SCSI_DH_RETRY) { 118 + if (--retry) 119 + goto retry; 222 120 ret = SCSI_DH_IO; 223 - done: 121 + } 122 + 123 + blk_put_request(req); 124 + 125 + return ret; 126 + } 127 + 128 + static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) 129 + { 130 + struct hp_sw_dh_data *h = get_hp_sw_data(sdev); 131 + int ret = BLKPREP_OK; 132 + 133 + if (h->path_state != HP_SW_PATH_ACTIVE) { 134 + ret = BLKPREP_KILL; 135 + req->cmd_flags |= REQ_QUIET; 136 + } 137 + return ret; 138 + 139 + } 140 + 141 + /* 142 + * hp_sw_activate - Activate a path 143 + * @sdev: sdev on the path to be activated 144 + * 145 + * The HP Active/Passive firmware is pretty simple; 146 + * the passive path reports NOT READY with sense codes 147 + * 0x04/0x02; a START STOP UNIT command will then 148 + * activate the passive path (and deactivate the 149 + * previously active one). 150 + */ 151 + static int hp_sw_activate(struct scsi_device *sdev) 152 + { 153 + int ret = SCSI_DH_OK; 154 + struct hp_sw_dh_data *h = get_hp_sw_data(sdev); 155 + 156 + ret = hp_sw_tur(sdev, h); 157 + 158 + if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { 159 + ret = hp_sw_start_stop(sdev, h); 160 + if (ret == SCSI_DH_OK) 161 + sdev_printk(KERN_INFO, sdev, 162 + "%s: activated path\n", 163 + HP_SW_NAME); 164 + } 165 + 224 166 return ret; 225 167 } 226 168 227 169 const struct scsi_dh_devlist hp_sw_dh_data_list[] = { 228 - {"COMPAQ", "MSA"}, 229 - {"HP", "HSV"}, 170 + {"COMPAQ", "MSA1000 VOLUME"}, 171 + {"COMPAQ", "HSV110"}, 172 + {"HP", "HSV100"}, 230 173 {"DEC", "HSG80"}, 231 174 {NULL, NULL}, 232 175 }; ··· 300 125 .attach = hp_sw_bus_attach, 301 126 .detach = hp_sw_bus_detach, 302 127 .activate = hp_sw_activate, 128 + .prep_fn = hp_sw_prep_fn, 303 129 }; 304 130 305 131 static int hp_sw_bus_attach(struct scsi_device *sdev) 306 132 { 307 133 struct scsi_dh_data *scsi_dh_data; 134 + struct hp_sw_dh_data *h; 308 135 unsigned long flags; 136 + int ret; 309 137 310 138 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) 311 139 + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); 312 140 if (!scsi_dh_data) { 313 - sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n", 141 + sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n", 314 142 HP_SW_NAME); 315 143 return 0; 316 144 } 317 145 318 146 scsi_dh_data->scsi_dh = &hp_sw_dh; 147 + h = (struct hp_sw_dh_data *) scsi_dh_data->buf; 148 + h->path_state = HP_SW_PATH_UNINITIALIZED; 149 + h->retries = HP_SW_RETRIES; 150 + 151 + ret = hp_sw_tur(sdev, h); 152 + if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED) 153 + goto failed; 154 + 155 + if (!try_module_get(THIS_MODULE)) 156 + goto failed; 157 + 319 158 spin_lock_irqsave(sdev->request_queue->queue_lock, flags); 320 159 sdev->scsi_dh_data = scsi_dh_data; 321 160 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 322 - try_module_get(THIS_MODULE); 323 161 324 - sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME); 162 + sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n", 163 + HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE? 164 + "active":"passive"); 325 165 326 166 return 0; 167 + 168 + failed: 169 + kfree(scsi_dh_data); 170 + sdev_printk(KERN_ERR, sdev, "%s: not attached\n", 171 + HP_SW_NAME); 172 + return -EINVAL; 327 173 } 328 174 329 175 static void hp_sw_bus_detach( struct scsi_device *sdev ) ··· 358 162 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 359 163 module_put(THIS_MODULE); 360 164 361 - sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", HP_SW_NAME); 165 + sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME); 362 166 363 167 kfree(scsi_dh_data); 364 168 } ··· 376 180 module_init(hp_sw_init); 377 181 module_exit(hp_sw_exit); 378 182 379 - MODULE_DESCRIPTION("HP MSA 1000"); 183 + MODULE_DESCRIPTION("HP Active/Passive driver"); 380 184 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu"); 381 185 MODULE_LICENSE("GPL");