[SCSI] scsi_dh: Update EMC handler

This patch converts the EMC device handler to use a proper
state machine. We now also parse the extended INQUIRY
information to determine if long trespass commands are
supported. And we're now using the long trespass command
correctly. And finally there's now an check at init time
to refuse to attach to devices not supporting EMC-specific
VPD pages.

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
b6ff1b14 4c05ae52

+373 -175
+372 -175
drivers/scsi/device_handler/scsi_dh_emc.c
··· 25 #include <scsi/scsi_dh.h> 26 #include <scsi/scsi_device.h> 27 28 - #define CLARIION_NAME "emc_clariion" 29 30 #define CLARIION_TRESPASS_PAGE 0x22 31 - #define CLARIION_BUFFER_SIZE 0x80 32 #define CLARIION_TIMEOUT (60 * HZ) 33 #define CLARIION_RETRIES 3 34 #define CLARIION_UNBOUND_LU -1 35 36 static unsigned char long_trespass[] = { 37 - 0, 0, 0, 0, 38 CLARIION_TRESPASS_PAGE, /* Page code */ 39 0x09, /* Page length - 2 */ 40 - 0x81, /* Trespass code + Honor reservation bit */ 41 - 0xff, 0xff, /* Trespass target */ 42 - 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ 43 - }; 44 - 45 - static unsigned char long_trespass_hr[] = { 46 - 0, 0, 0, 0, 47 - CLARIION_TRESPASS_PAGE, /* Page code */ 48 - 0x09, /* Page length - 2 */ 49 - 0x01, /* Trespass code + Honor reservation bit */ 50 0xff, 0xff, /* Trespass target */ 51 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ 52 }; ··· 58 0, 0, 0, 0, 59 CLARIION_TRESPASS_PAGE, /* Page code */ 60 0x02, /* Page length - 2 */ 61 - 0x81, /* Trespass code + Honor reservation bit */ 62 0xff, /* Trespass target */ 63 }; 64 65 - static unsigned char short_trespass_hr[] = { 66 - 0, 0, 0, 0, 67 - CLARIION_TRESPASS_PAGE, /* Page code */ 68 - 0x02, /* Page length - 2 */ 69 - 0x01, /* Trespass code + Honor reservation bit */ 70 - 0xff, /* Trespass target */ 71 }; 72 73 struct clariion_dh_data { 74 /* 75 * Use short trespass command (FC-series) or the long version 76 * (default for AX/CX CLARiiON arrays). 77 - */ 78 - unsigned short_trespass; 79 - /* 80 * Whether or not (default) to honor SCSI reservations when 81 * initiating a switch-over. 82 */ 83 - unsigned hr; 84 - /* I/O buffer for both MODE_SELECT and INQUIRY commands. */ 85 char buffer[CLARIION_BUFFER_SIZE]; 86 /* 87 * SCSI sense buffer for commands -- assumes serial issuance 88 * and completion sequence of all commands for same multipath. 89 */ 90 unsigned char sense[SCSI_SENSE_BUFFERSIZE]; 91 - /* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */ 92 int default_sp; 93 - /* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */ 94 int current_sp; 95 }; 96 ··· 122 /* 123 * Parse MODE_SELECT cmd reply. 124 */ 125 - static int trespass_endio(struct scsi_device *sdev, int result) 126 { 127 - int err = SCSI_DH_OK; 128 struct scsi_sense_hdr sshdr; 129 - struct clariion_dh_data *csdev = get_clariion_data(sdev); 130 - char *sense = csdev->sense; 131 132 - if (status_byte(result) == CHECK_CONDITION && 133 - scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { 134 - sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, " 135 "0x%2x, 0x%2x while sending CLARiiON trespass " 136 - "command.\n", sshdr.sense_key, sshdr.asc, 137 - sshdr.ascq); 138 139 if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && 140 (sshdr.ascq == 0x00)) { ··· 139 * Array based copy in progress -- do not send 140 * mode_select or copy will be aborted mid-stream. 141 */ 142 - sdev_printk(KERN_INFO, sdev, "Array Based Copy in " 143 "progress while sending CLARiiON trespass " 144 - "command.\n"); 145 err = SCSI_DH_DEV_TEMP_BUSY; 146 } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && 147 (sshdr.ascq == 0x03)) { ··· 149 * LUN Not Ready - Manual Intervention Required 150 * indicates in-progress ucode upgrade (NDU). 151 */ 152 - sdev_printk(KERN_INFO, sdev, "Detected in-progress " 153 "ucode upgrade NDU operation while sending " 154 - "CLARiiON trespass command.\n"); 155 err = SCSI_DH_DEV_TEMP_BUSY; 156 } else 157 err = SCSI_DH_DEV_FAILED; 158 - } else if (result) { 159 - sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending " 160 - "CLARiiON trespass command.\n", result); 161 - err = SCSI_DH_IO; 162 } 163 - 164 return err; 165 } 166 167 - static int parse_sp_info_reply(struct scsi_device *sdev, int result, 168 - int *default_sp, int *current_sp, int *new_current_sp) 169 { 170 int err = SCSI_DH_OK; 171 - struct clariion_dh_data *csdev = get_clariion_data(sdev); 172 173 - if (result == 0) { 174 - /* check for in-progress ucode upgrade (NDU) */ 175 - if (csdev->buffer[48] != 0) { 176 - sdev_printk(KERN_NOTICE, sdev, "Detected in-progress " 177 - "ucode upgrade NDU operation while finding " 178 - "current active SP."); 179 - err = SCSI_DH_DEV_TEMP_BUSY; 180 - } else { 181 - *default_sp = csdev->buffer[5]; 182 - 183 - if (csdev->buffer[4] == 2) 184 - /* SP for path is current */ 185 - *current_sp = csdev->buffer[8]; 186 - else { 187 - if (csdev->buffer[4] == 1) 188 - /* SP for this path is NOT current */ 189 - if (csdev->buffer[8] == 0) 190 - *current_sp = 1; 191 - else 192 - *current_sp = 0; 193 - else 194 - /* unbound LU or LUNZ */ 195 - *current_sp = CLARIION_UNBOUND_LU; 196 - } 197 - *new_current_sp = csdev->buffer[8]; 198 - } 199 - } else { 200 - struct scsi_sense_hdr sshdr; 201 - 202 - err = SCSI_DH_IO; 203 - 204 - if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, 205 - &sshdr)) 206 - sdev_printk(KERN_ERR, sdev, "Found valid sense data " 207 - "0x%2x, 0x%2x, 0x%2x while finding current " 208 - "active SP.", sshdr.sense_key, sshdr.asc, 209 - sshdr.ascq); 210 - else 211 - sdev_printk(KERN_ERR, sdev, "Error 0x%x finding " 212 - "current active SP.", result); 213 } 214 215 return err; 216 } 217 218 - static int sp_info_endio(struct scsi_device *sdev, int result, 219 - int mode_select_sent, int *done) 220 { 221 - struct clariion_dh_data *csdev = get_clariion_data(sdev); 222 - int err_flags, default_sp, current_sp, new_current_sp; 223 224 - err_flags = parse_sp_info_reply(sdev, result, &default_sp, 225 - &current_sp, &new_current_sp); 226 - 227 - if (err_flags != SCSI_DH_OK) 228 - goto done; 229 - 230 - if (mode_select_sent) { 231 - csdev->default_sp = default_sp; 232 - csdev->current_sp = current_sp; 233 - } else { 234 - /* 235 - * Issue the actual module_selec request IFF either 236 - * (1) we do not know the identity of the current SP OR 237 - * (2) what we think we know is actually correct. 238 - */ 239 - if ((current_sp != CLARIION_UNBOUND_LU) && 240 - (new_current_sp != current_sp)) { 241 - 242 - csdev->default_sp = default_sp; 243 - csdev->current_sp = current_sp; 244 - 245 - sdev_printk(KERN_INFO, sdev, "Ignoring path group " 246 - "switch-over command for CLARiiON SP%s since " 247 - " mapped device is already initialized.", 248 - current_sp ? "B" : "A"); 249 - if (done) 250 - *done = 1; /* as good as doing it */ 251 } 252 } 253 - done: 254 - return err_flags; 255 } 256 257 /* ··· 265 * Uses data and sense buffers in hardware handler context structure and 266 * assumes serial servicing of commands, both issuance and completion. 267 */ 268 - static struct request *get_req(struct scsi_device *sdev, int cmd) 269 { 270 - struct clariion_dh_data *csdev = get_clariion_data(sdev); 271 struct request *rq; 272 - unsigned char *page22; 273 int len = 0; 274 275 rq = blk_get_request(sdev->request_queue, 276 - (cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC); 277 if (!rq) { 278 sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); 279 return NULL; 280 } 281 282 - memset(&rq->cmd, 0, BLK_MAX_CDB); 283 rq->cmd[0] = cmd; 284 - rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); 285 286 switch (cmd) { 287 case MODE_SELECT: 288 - if (csdev->short_trespass) { 289 - page22 = csdev->hr ? short_trespass_hr : short_trespass; 290 - len = sizeof(short_trespass); 291 - } else { 292 - page22 = csdev->hr ? long_trespass_hr : long_trespass; 293 - len = sizeof(long_trespass); 294 - } 295 - /* 296 - * Can't DMA from kernel BSS -- must copy selected trespass 297 - * command mode page contents to context buffer which is 298 - * allocated by kmalloc. 299 - */ 300 - BUG_ON((len > CLARIION_BUFFER_SIZE)); 301 - memcpy(csdev->buffer, page22, len); 302 rq->cmd_flags |= REQ_RW; 303 rq->cmd[1] = 0x10; 304 break; 305 case INQUIRY: 306 - rq->cmd[1] = 0x1; 307 - rq->cmd[2] = 0xC0; 308 len = CLARIION_BUFFER_SIZE; 309 - memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE); 310 break; 311 default: 312 BUG_ON(1); ··· 308 rq->timeout = CLARIION_TIMEOUT; 309 rq->retries = CLARIION_RETRIES; 310 311 - rq->sense = csdev->sense; 312 - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); 313 - rq->sense_len = 0; 314 - 315 - if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer, 316 - len, GFP_ATOMIC)) { 317 - __blk_put_request(rq->q, rq); 318 return NULL; 319 } 320 321 return rq; 322 } 323 324 - static int send_cmd(struct scsi_device *sdev, int cmd) 325 { 326 - struct request *rq = get_req(sdev, cmd); 327 328 if (!rq) 329 return SCSI_DH_RES_TEMP_UNAVAIL; 330 331 - return blk_execute_rq(sdev->request_queue, NULL, rq, 1); 332 } 333 334 - static int clariion_activate(struct scsi_device *sdev) 335 { 336 - int result, done = 0; 337 338 - result = send_cmd(sdev, INQUIRY); 339 - result = sp_info_endio(sdev, result, 0, &done); 340 - if (result || done) 341 - goto done; 342 343 - result = send_cmd(sdev, MODE_SELECT); 344 - result = trespass_endio(sdev, result); 345 - if (result) 346 - goto done; 347 348 - result = send_cmd(sdev, INQUIRY); 349 - result = sp_info_endio(sdev, result, 1, NULL); 350 - done: 351 - return result; 352 } 353 354 static int clariion_check_sense(struct scsi_device *sdev, ··· 443 break; 444 } 445 446 - /* success just means we do not care what scsi-ml does */ 447 - return SUCCESS; 448 } 449 450 const struct scsi_dh_devlist clariion_dev_list[] = { 451 {"DGC", "RAID"}, 452 {"DGC", "DISK"}, 453 {NULL, NULL}, 454 }; 455 ··· 580 .detach = clariion_bus_detach, 581 .check_sense = clariion_check_sense, 582 .activate = clariion_activate, 583 }; 584 585 /* ··· 591 struct scsi_dh_data *scsi_dh_data; 592 struct clariion_dh_data *h; 593 unsigned long flags; 594 595 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) 596 + sizeof(*h) , GFP_KERNEL); 597 if (!scsi_dh_data) { 598 - sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", 599 CLARIION_NAME); 600 return -ENOMEM; 601 } 602 603 scsi_dh_data->scsi_dh = &clariion_dh; 604 h = (struct clariion_dh_data *) scsi_dh_data->buf; 605 h->default_sp = CLARIION_UNBOUND_LU; 606 h->current_sp = CLARIION_UNBOUND_LU; 607 608 spin_lock_irqsave(sdev->request_queue->queue_lock, flags); 609 sdev->scsi_dh_data = scsi_dh_data; 610 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 611 612 - sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); 613 - try_module_get(THIS_MODULE); 614 615 return 0; 616 } 617 618 static void clariion_bus_detach(struct scsi_device *sdev) ··· 647 sdev->scsi_dh_data = NULL; 648 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 649 650 - sdev_printk(KERN_NOTICE, sdev, "Detached %s.\n", 651 CLARIION_NAME); 652 653 kfree(scsi_dh_data); ··· 660 661 r = scsi_register_device_handler(&clariion_dh); 662 if (r != 0) 663 - printk(KERN_ERR "Failed to register scsi device handler."); 664 return r; 665 } 666
··· 25 #include <scsi/scsi_dh.h> 26 #include <scsi/scsi_device.h> 27 28 + #define CLARIION_NAME "emc" 29 30 #define CLARIION_TRESPASS_PAGE 0x22 31 + #define CLARIION_BUFFER_SIZE 0xFC 32 #define CLARIION_TIMEOUT (60 * HZ) 33 #define CLARIION_RETRIES 3 34 #define CLARIION_UNBOUND_LU -1 35 + #define CLARIION_SP_A 0 36 + #define CLARIION_SP_B 1 37 + 38 + /* Flags */ 39 + #define CLARIION_SHORT_TRESPASS 1 40 + #define CLARIION_HONOR_RESERVATIONS 2 41 + 42 + /* LUN states */ 43 + #define CLARIION_LUN_UNINITIALIZED -1 44 + #define CLARIION_LUN_UNBOUND 0 45 + #define CLARIION_LUN_BOUND 1 46 + #define CLARIION_LUN_OWNED 2 47 48 static unsigned char long_trespass[] = { 49 + 0, 0, 0, 0, 0, 0, 0, 0, 50 CLARIION_TRESPASS_PAGE, /* Page code */ 51 0x09, /* Page length - 2 */ 52 + 0x01, /* Trespass code */ 53 0xff, 0xff, /* Trespass target */ 54 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ 55 }; ··· 55 0, 0, 0, 0, 56 CLARIION_TRESPASS_PAGE, /* Page code */ 57 0x02, /* Page length - 2 */ 58 + 0x01, /* Trespass code */ 59 0xff, /* Trespass target */ 60 }; 61 62 + static const char * lun_state[] = 63 + { 64 + "not bound", 65 + "bound", 66 + "owned", 67 }; 68 69 struct clariion_dh_data { 70 /* 71 + * Flags: 72 + * CLARIION_SHORT_TRESPASS 73 * Use short trespass command (FC-series) or the long version 74 * (default for AX/CX CLARiiON arrays). 75 + * 76 + * CLARIION_HONOR_RESERVATIONS 77 * Whether or not (default) to honor SCSI reservations when 78 * initiating a switch-over. 79 */ 80 + unsigned flags; 81 + /* 82 + * I/O buffer for both MODE_SELECT and INQUIRY commands. 83 + */ 84 char buffer[CLARIION_BUFFER_SIZE]; 85 /* 86 * SCSI sense buffer for commands -- assumes serial issuance 87 * and completion sequence of all commands for same multipath. 88 */ 89 unsigned char sense[SCSI_SENSE_BUFFERSIZE]; 90 + unsigned int senselen; 91 + /* 92 + * LUN state 93 + */ 94 + int lun_state; 95 + /* 96 + * SP Port number 97 + */ 98 + int port; 99 + /* 100 + * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this 101 + * path's mapped LUN 102 + */ 103 int default_sp; 104 + /* 105 + * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this 106 + * path's mapped LUN 107 + */ 108 int current_sp; 109 }; 110 ··· 102 /* 103 * Parse MODE_SELECT cmd reply. 104 */ 105 + static int trespass_endio(struct scsi_device *sdev, char *sense) 106 { 107 + int err = SCSI_DH_IO; 108 struct scsi_sense_hdr sshdr; 109 110 + if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { 111 + sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, " 112 "0x%2x, 0x%2x while sending CLARiiON trespass " 113 + "command.\n", CLARIION_NAME, sshdr.sense_key, 114 + sshdr.asc, sshdr.ascq); 115 116 if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && 117 (sshdr.ascq == 0x00)) { ··· 122 * Array based copy in progress -- do not send 123 * mode_select or copy will be aborted mid-stream. 124 */ 125 + sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in " 126 "progress while sending CLARiiON trespass " 127 + "command.\n", CLARIION_NAME); 128 err = SCSI_DH_DEV_TEMP_BUSY; 129 } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && 130 (sshdr.ascq == 0x03)) { ··· 132 * LUN Not Ready - Manual Intervention Required 133 * indicates in-progress ucode upgrade (NDU). 134 */ 135 + sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress " 136 "ucode upgrade NDU operation while sending " 137 + "CLARiiON trespass command.\n", CLARIION_NAME); 138 err = SCSI_DH_DEV_TEMP_BUSY; 139 } else 140 err = SCSI_DH_DEV_FAILED; 141 + } else { 142 + sdev_printk(KERN_INFO, sdev, 143 + "%s: failed to send MODE SELECT, no sense available\n", 144 + CLARIION_NAME); 145 } 146 return err; 147 } 148 149 + static int parse_sp_info_reply(struct scsi_device *sdev, 150 + struct clariion_dh_data *csdev) 151 { 152 int err = SCSI_DH_OK; 153 154 + /* check for in-progress ucode upgrade (NDU) */ 155 + if (csdev->buffer[48] != 0) { 156 + sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress " 157 + "ucode upgrade NDU operation while finding " 158 + "current active SP.", CLARIION_NAME); 159 + err = SCSI_DH_DEV_TEMP_BUSY; 160 + goto out; 161 + } 162 + if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) { 163 + /* Invalid buffer format */ 164 + sdev_printk(KERN_NOTICE, sdev, 165 + "%s: invalid VPD page 0xC0 format\n", 166 + CLARIION_NAME); 167 + err = SCSI_DH_NOSYS; 168 + goto out; 169 + } 170 + switch (csdev->buffer[28] & 0x0f) { 171 + case 6: 172 + sdev_printk(KERN_NOTICE, sdev, 173 + "%s: ALUA failover mode detected\n", 174 + CLARIION_NAME); 175 + break; 176 + case 4: 177 + /* Linux failover */ 178 + break; 179 + default: 180 + sdev_printk(KERN_WARNING, sdev, 181 + "%s: Invalid failover mode %d\n", 182 + CLARIION_NAME, csdev->buffer[28] & 0x0f); 183 + err = SCSI_DH_NOSYS; 184 + goto out; 185 } 186 187 + csdev->default_sp = csdev->buffer[5]; 188 + csdev->lun_state = csdev->buffer[4]; 189 + csdev->current_sp = csdev->buffer[8]; 190 + csdev->port = csdev->buffer[7]; 191 + 192 + out: 193 return err; 194 } 195 196 + #define emc_default_str "FC (Legacy)" 197 + 198 + static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer) 199 { 200 + unsigned char len = buffer[4] + 5; 201 + char *sp_model = NULL; 202 + unsigned char sp_len, serial_len; 203 204 + if (len < 160) { 205 + sdev_printk(KERN_WARNING, sdev, 206 + "%s: Invalid information section length %d\n", 207 + CLARIION_NAME, len); 208 + /* Check for old FC arrays */ 209 + if (!strncmp(buffer + 8, "DGC", 3)) { 210 + /* Old FC array, not supporting extended information */ 211 + sp_model = emc_default_str; 212 } 213 + goto out; 214 } 215 + 216 + /* 217 + * Parse extended information for SP model number 218 + */ 219 + serial_len = buffer[160]; 220 + if (serial_len == 0 || serial_len + 161 > len) { 221 + sdev_printk(KERN_WARNING, sdev, 222 + "%s: Invalid array serial number length %d\n", 223 + CLARIION_NAME, serial_len); 224 + goto out; 225 + } 226 + sp_len = buffer[99]; 227 + if (sp_len == 0 || serial_len + sp_len + 161 > len) { 228 + sdev_printk(KERN_WARNING, sdev, 229 + "%s: Invalid model number length %d\n", 230 + CLARIION_NAME, sp_len); 231 + goto out; 232 + } 233 + sp_model = &buffer[serial_len + 161]; 234 + /* Strip whitespace at the end */ 235 + while (sp_len > 1 && sp_model[sp_len - 1] == ' ') 236 + sp_len--; 237 + 238 + sp_model[sp_len] = '\0'; 239 + 240 + out: 241 + return sp_model; 242 } 243 244 /* ··· 244 * Uses data and sense buffers in hardware handler context structure and 245 * assumes serial servicing of commands, both issuance and completion. 246 */ 247 + static struct request *get_req(struct scsi_device *sdev, int cmd, 248 + unsigned char *buffer) 249 { 250 struct request *rq; 251 int len = 0; 252 253 rq = blk_get_request(sdev->request_queue, 254 + (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO); 255 if (!rq) { 256 sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); 257 return NULL; 258 } 259 260 + memset(rq->cmd, 0, BLK_MAX_CDB); 261 + rq->cmd_len = COMMAND_SIZE(cmd); 262 rq->cmd[0] = cmd; 263 264 switch (cmd) { 265 case MODE_SELECT: 266 + len = sizeof(short_trespass); 267 + rq->cmd_flags |= REQ_RW; 268 + rq->cmd[1] = 0x10; 269 + break; 270 + case MODE_SELECT_10: 271 + len = sizeof(long_trespass); 272 rq->cmd_flags |= REQ_RW; 273 rq->cmd[1] = 0x10; 274 break; 275 case INQUIRY: 276 len = CLARIION_BUFFER_SIZE; 277 + memset(buffer, 0, len); 278 break; 279 default: 280 BUG_ON(1); ··· 298 rq->timeout = CLARIION_TIMEOUT; 299 rq->retries = CLARIION_RETRIES; 300 301 + if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) { 302 + blk_put_request(rq); 303 return NULL; 304 } 305 306 return rq; 307 } 308 309 + static int send_inquiry_cmd(struct scsi_device *sdev, int page, 310 + struct clariion_dh_data *csdev) 311 { 312 + struct request *rq = get_req(sdev, INQUIRY, csdev->buffer); 313 + int err; 314 315 if (!rq) 316 return SCSI_DH_RES_TEMP_UNAVAIL; 317 318 + rq->sense = csdev->sense; 319 + memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); 320 + rq->sense_len = csdev->senselen = 0; 321 + 322 + rq->cmd[0] = INQUIRY; 323 + if (page != 0) { 324 + rq->cmd[1] = 1; 325 + rq->cmd[2] = page; 326 + } 327 + err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); 328 + if (err == -EIO) { 329 + sdev_printk(KERN_INFO, sdev, 330 + "%s: failed to send %s INQUIRY: %x\n", 331 + CLARIION_NAME, page?"EVPD":"standard", 332 + rq->errors); 333 + csdev->senselen = rq->sense_len; 334 + err = SCSI_DH_IO; 335 + } 336 + 337 + blk_put_request(rq); 338 + 339 + return err; 340 } 341 342 + static int send_trespass_cmd(struct scsi_device *sdev, 343 + struct clariion_dh_data *csdev) 344 { 345 + struct request *rq; 346 + unsigned char *page22; 347 + int err, len, cmd; 348 349 + if (csdev->flags & CLARIION_SHORT_TRESPASS) { 350 + page22 = short_trespass; 351 + if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) 352 + /* Set Honor Reservations bit */ 353 + page22[6] |= 0x80; 354 + len = sizeof(short_trespass); 355 + cmd = MODE_SELECT; 356 + } else { 357 + page22 = long_trespass; 358 + if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) 359 + /* Set Honor Reservations bit */ 360 + page22[10] |= 0x80; 361 + len = sizeof(long_trespass); 362 + cmd = MODE_SELECT_10; 363 + } 364 + BUG_ON((len > CLARIION_BUFFER_SIZE)); 365 + memcpy(csdev->buffer, page22, len); 366 367 + rq = get_req(sdev, cmd, csdev->buffer); 368 + if (!rq) 369 + return SCSI_DH_RES_TEMP_UNAVAIL; 370 371 + rq->sense = csdev->sense; 372 + memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); 373 + rq->sense_len = csdev->senselen = 0; 374 + 375 + err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); 376 + if (err == -EIO) { 377 + if (rq->sense_len) { 378 + err = trespass_endio(sdev, csdev->sense); 379 + } else { 380 + sdev_printk(KERN_INFO, sdev, 381 + "%s: failed to send MODE SELECT: %x\n", 382 + CLARIION_NAME, rq->errors); 383 + } 384 + } 385 + 386 + blk_put_request(rq); 387 + 388 + return err; 389 } 390 391 static int clariion_check_sense(struct scsi_device *sdev, ··· 386 break; 387 } 388 389 + return SCSI_RETURN_NOT_HANDLED; 390 + } 391 + 392 + static int clariion_prep_fn(struct scsi_device *sdev, struct request *req) 393 + { 394 + struct clariion_dh_data *h = get_clariion_data(sdev); 395 + int ret = BLKPREP_OK; 396 + 397 + if (h->lun_state != CLARIION_LUN_OWNED) { 398 + ret = BLKPREP_KILL; 399 + req->cmd_flags |= REQ_QUIET; 400 + } 401 + return ret; 402 + 403 + } 404 + 405 + static int clariion_std_inquiry(struct scsi_device *sdev, 406 + struct clariion_dh_data *csdev) 407 + { 408 + int err; 409 + char *sp_model; 410 + 411 + err = send_inquiry_cmd(sdev, 0, csdev); 412 + if (err != SCSI_DH_OK && csdev->senselen) { 413 + struct scsi_sense_hdr sshdr; 414 + 415 + if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, 416 + &sshdr)) { 417 + sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " 418 + "%02x/%02x/%02x\n", CLARIION_NAME, 419 + sshdr.sense_key, sshdr.asc, sshdr.ascq); 420 + } 421 + err = SCSI_DH_IO; 422 + goto out; 423 + } 424 + 425 + sp_model = parse_sp_model(sdev, csdev->buffer); 426 + if (!sp_model) { 427 + err = SCSI_DH_DEV_UNSUPP; 428 + goto out; 429 + } 430 + 431 + /* 432 + * FC Series arrays do not support long trespass 433 + */ 434 + if (!strlen(sp_model) || !strncmp(sp_model, "FC",2)) 435 + csdev->flags |= CLARIION_SHORT_TRESPASS; 436 + 437 + sdev_printk(KERN_INFO, sdev, 438 + "%s: detected Clariion %s, flags %x\n", 439 + CLARIION_NAME, sp_model, csdev->flags); 440 + out: 441 + return err; 442 + } 443 + 444 + static int clariion_send_inquiry(struct scsi_device *sdev, 445 + struct clariion_dh_data *csdev) 446 + { 447 + int err, retry = CLARIION_RETRIES; 448 + 449 + retry: 450 + err = send_inquiry_cmd(sdev, 0xC0, csdev); 451 + if (err != SCSI_DH_OK && csdev->senselen) { 452 + struct scsi_sense_hdr sshdr; 453 + 454 + err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, 455 + &sshdr); 456 + if (!err) 457 + return SCSI_DH_IO; 458 + 459 + err = clariion_check_sense(sdev, &sshdr); 460 + if (retry > 0 && err == NEEDS_RETRY) { 461 + retry--; 462 + goto retry; 463 + } 464 + sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " 465 + "%02x/%02x/%02x\n", CLARIION_NAME, 466 + sshdr.sense_key, sshdr.asc, sshdr.ascq); 467 + err = SCSI_DH_IO; 468 + } else { 469 + err = parse_sp_info_reply(sdev, csdev); 470 + } 471 + return err; 472 + } 473 + 474 + static int clariion_activate(struct scsi_device *sdev) 475 + { 476 + struct clariion_dh_data *csdev = get_clariion_data(sdev); 477 + int result; 478 + 479 + result = clariion_send_inquiry(sdev, csdev); 480 + if (result != SCSI_DH_OK) 481 + goto done; 482 + 483 + if (csdev->lun_state == CLARIION_LUN_OWNED) 484 + goto done; 485 + 486 + result = send_trespass_cmd(sdev, csdev); 487 + if (result != SCSI_DH_OK) 488 + goto done; 489 + sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n", 490 + CLARIION_NAME, 491 + csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" ); 492 + 493 + /* Update status */ 494 + result = clariion_send_inquiry(sdev, csdev); 495 + if (result != SCSI_DH_OK) 496 + goto done; 497 + 498 + done: 499 + sdev_printk(KERN_INFO, sdev, 500 + "%s: at SP %c Port %d (%s, default SP %c)\n", 501 + CLARIION_NAME, csdev->current_sp + 'A', 502 + csdev->port, lun_state[csdev->lun_state], 503 + csdev->default_sp + 'A'); 504 + 505 + return result; 506 } 507 508 const struct scsi_dh_devlist clariion_dev_list[] = { 509 {"DGC", "RAID"}, 510 {"DGC", "DISK"}, 511 + {"DGC", "VRAID"}, 512 {NULL, NULL}, 513 }; 514 ··· 407 .detach = clariion_bus_detach, 408 .check_sense = clariion_check_sense, 409 .activate = clariion_activate, 410 + .prep_fn = clariion_prep_fn, 411 }; 412 413 /* ··· 417 struct scsi_dh_data *scsi_dh_data; 418 struct clariion_dh_data *h; 419 unsigned long flags; 420 + int err; 421 422 scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) 423 + sizeof(*h) , GFP_KERNEL); 424 if (!scsi_dh_data) { 425 + sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", 426 CLARIION_NAME); 427 return -ENOMEM; 428 } 429 430 scsi_dh_data->scsi_dh = &clariion_dh; 431 h = (struct clariion_dh_data *) scsi_dh_data->buf; 432 + h->lun_state = CLARIION_LUN_UNINITIALIZED; 433 h->default_sp = CLARIION_UNBOUND_LU; 434 h->current_sp = CLARIION_UNBOUND_LU; 435 + 436 + err = clariion_std_inquiry(sdev, h); 437 + if (err != SCSI_DH_OK) 438 + goto failed; 439 + 440 + err = clariion_send_inquiry(sdev, h); 441 + if (err != SCSI_DH_OK) 442 + goto failed; 443 + 444 + if (!try_module_get(THIS_MODULE)) 445 + goto failed; 446 447 spin_lock_irqsave(sdev->request_queue->queue_lock, flags); 448 sdev->scsi_dh_data = scsi_dh_data; 449 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 450 451 + sdev_printk(KERN_INFO, sdev, 452 + "%s: connected to SP %c Port %d (%s, default SP %c)\n", 453 + CLARIION_NAME, h->current_sp + 'A', 454 + h->port, lun_state[h->lun_state], 455 + h->default_sp + 'A'); 456 457 return 0; 458 + 459 + failed: 460 + kfree(scsi_dh_data); 461 + sdev_printk(KERN_ERR, sdev, "%s: not attached\n", 462 + CLARIION_NAME); 463 + return -EINVAL; 464 } 465 466 static void clariion_bus_detach(struct scsi_device *sdev) ··· 451 sdev->scsi_dh_data = NULL; 452 spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); 453 454 + sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", 455 CLARIION_NAME); 456 457 kfree(scsi_dh_data); ··· 464 465 r = scsi_register_device_handler(&clariion_dh); 466 if (r != 0) 467 + printk(KERN_ERR "%s: Failed to register scsi device handler.", 468 + CLARIION_NAME); 469 return r; 470 } 471
+1
include/scsi/scsi_dh.h
··· 32 */ 33 SCSI_DH_DEV_FAILED, /* generic device error */ 34 SCSI_DH_DEV_TEMP_BUSY, 35 SCSI_DH_DEVICE_MAX, /* max device blkerr definition */ 36 37 /*
··· 32 */ 33 SCSI_DH_DEV_FAILED, /* generic device error */ 34 SCSI_DH_DEV_TEMP_BUSY, 35 + SCSI_DH_DEV_UNSUPP, /* device handler not supported */ 36 SCSI_DH_DEVICE_MAX, /* max device blkerr definition */ 37 38 /*