diff options
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_rdac.c | 163 |
1 files changed, 94 insertions, 69 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 0e25a6e9c82d..b093a501f8ae 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c | |||
@@ -173,6 +173,11 @@ struct rdac_dh_data { | |||
173 | #define RDAC_STATE_ACTIVE 0 | 173 | #define RDAC_STATE_ACTIVE 0 |
174 | #define RDAC_STATE_PASSIVE 1 | 174 | #define RDAC_STATE_PASSIVE 1 |
175 | unsigned char state; | 175 | unsigned char state; |
176 | |||
177 | #define RDAC_LUN_UNOWNED 0 | ||
178 | #define RDAC_LUN_OWNED 1 | ||
179 | #define RDAC_LUN_AVT 2 | ||
180 | char lun_state; | ||
176 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 181 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
177 | union { | 182 | union { |
178 | struct c2_inquiry c2; | 183 | struct c2_inquiry c2; |
@@ -182,6 +187,13 @@ struct rdac_dh_data { | |||
182 | } inq; | 187 | } inq; |
183 | }; | 188 | }; |
184 | 189 | ||
190 | static const char *lun_state[] = | ||
191 | { | ||
192 | "unowned", | ||
193 | "owned", | ||
194 | "owned (AVT mode)", | ||
195 | }; | ||
196 | |||
185 | static LIST_HEAD(ctlr_list); | 197 | static LIST_HEAD(ctlr_list); |
186 | static DEFINE_SPINLOCK(list_lock); | 198 | static DEFINE_SPINLOCK(list_lock); |
187 | 199 | ||
@@ -197,9 +209,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev, | |||
197 | { | 209 | { |
198 | struct request *rq; | 210 | struct request *rq; |
199 | struct request_queue *q = sdev->request_queue; | 211 | struct request_queue *q = sdev->request_queue; |
200 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
201 | 212 | ||
202 | rq = blk_get_request(q, rw, GFP_KERNEL); | 213 | rq = blk_get_request(q, rw, GFP_NOIO); |
203 | 214 | ||
204 | if (!rq) { | 215 | if (!rq) { |
205 | sdev_printk(KERN_INFO, sdev, | 216 | sdev_printk(KERN_INFO, sdev, |
@@ -207,17 +218,14 @@ static struct request *get_rdac_req(struct scsi_device *sdev, | |||
207 | return NULL; | 218 | return NULL; |
208 | } | 219 | } |
209 | 220 | ||
210 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) { | 221 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { |
211 | blk_put_request(rq); | 222 | blk_put_request(rq); |
212 | sdev_printk(KERN_INFO, sdev, | 223 | sdev_printk(KERN_INFO, sdev, |
213 | "get_rdac_req: blk_rq_map_kern failed.\n"); | 224 | "get_rdac_req: blk_rq_map_kern failed.\n"); |
214 | return NULL; | 225 | return NULL; |
215 | } | 226 | } |
216 | 227 | ||
217 | memset(&rq->cmd, 0, BLK_MAX_CDB); | 228 | memset(rq->cmd, 0, BLK_MAX_CDB); |
218 | rq->sense = h->sense; | ||
219 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
220 | rq->sense_len = 0; | ||
221 | 229 | ||
222 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | 230 | rq->cmd_type = REQ_TYPE_BLOCK_PC; |
223 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | 231 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; |
@@ -227,12 +235,12 @@ static struct request *get_rdac_req(struct scsi_device *sdev, | |||
227 | return rq; | 235 | return rq; |
228 | } | 236 | } |
229 | 237 | ||
230 | static struct request *rdac_failover_get(struct scsi_device *sdev) | 238 | static struct request *rdac_failover_get(struct scsi_device *sdev, |
239 | struct rdac_dh_data *h) | ||
231 | { | 240 | { |
232 | struct request *rq; | 241 | struct request *rq; |
233 | struct rdac_mode_common *common; | 242 | struct rdac_mode_common *common; |
234 | unsigned data_size; | 243 | unsigned data_size; |
235 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
236 | 244 | ||
237 | if (h->ctlr->use_ms10) { | 245 | if (h->ctlr->use_ms10) { |
238 | struct rdac_pg_expanded *rdac_pg; | 246 | struct rdac_pg_expanded *rdac_pg; |
@@ -277,6 +285,10 @@ static struct request *rdac_failover_get(struct scsi_device *sdev) | |||
277 | } | 285 | } |
278 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | 286 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); |
279 | 287 | ||
288 | rq->sense = h->sense; | ||
289 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
290 | rq->sense_len = 0; | ||
291 | |||
280 | return rq; | 292 | return rq; |
281 | } | 293 | } |
282 | 294 | ||
@@ -321,11 +333,10 @@ done: | |||
321 | } | 333 | } |
322 | 334 | ||
323 | static int submit_inquiry(struct scsi_device *sdev, int page_code, | 335 | static int submit_inquiry(struct scsi_device *sdev, int page_code, |
324 | unsigned int len) | 336 | unsigned int len, struct rdac_dh_data *h) |
325 | { | 337 | { |
326 | struct request *rq; | 338 | struct request *rq; |
327 | struct request_queue *q = sdev->request_queue; | 339 | struct request_queue *q = sdev->request_queue; |
328 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
329 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | 340 | int err = SCSI_DH_RES_TEMP_UNAVAIL; |
330 | 341 | ||
331 | rq = get_rdac_req(sdev, &h->inq, len, READ); | 342 | rq = get_rdac_req(sdev, &h->inq, len, READ); |
@@ -338,59 +349,68 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code, | |||
338 | rq->cmd[2] = page_code; | 349 | rq->cmd[2] = page_code; |
339 | rq->cmd[4] = len; | 350 | rq->cmd[4] = len; |
340 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | 351 | rq->cmd_len = COMMAND_SIZE(INQUIRY); |
352 | |||
353 | rq->sense = h->sense; | ||
354 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
355 | rq->sense_len = 0; | ||
356 | |||
341 | err = blk_execute_rq(q, NULL, rq, 1); | 357 | err = blk_execute_rq(q, NULL, rq, 1); |
342 | if (err == -EIO) | 358 | if (err == -EIO) |
343 | err = SCSI_DH_IO; | 359 | err = SCSI_DH_IO; |
360 | |||
361 | blk_put_request(rq); | ||
344 | done: | 362 | done: |
345 | return err; | 363 | return err; |
346 | } | 364 | } |
347 | 365 | ||
348 | static int get_lun(struct scsi_device *sdev) | 366 | static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h) |
349 | { | 367 | { |
350 | int err; | 368 | int err; |
351 | struct c8_inquiry *inqp; | 369 | struct c8_inquiry *inqp; |
352 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
353 | 370 | ||
354 | err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry)); | 371 | err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h); |
355 | if (err == SCSI_DH_OK) { | 372 | if (err == SCSI_DH_OK) { |
356 | inqp = &h->inq.c8; | 373 | inqp = &h->inq.c8; |
357 | h->lun = inqp->lun[7]; /* currently it uses only one byte */ | 374 | if (inqp->page_code != 0xc8) |
375 | return SCSI_DH_NOSYS; | ||
376 | if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' || | ||
377 | inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd') | ||
378 | return SCSI_DH_NOSYS; | ||
379 | h->lun = scsilun_to_int((struct scsi_lun *)inqp->lun); | ||
358 | } | 380 | } |
359 | return err; | 381 | return err; |
360 | } | 382 | } |
361 | 383 | ||
362 | #define RDAC_OWNED 0 | 384 | static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) |
363 | #define RDAC_UNOWNED 1 | ||
364 | #define RDAC_FAILED 2 | ||
365 | static int check_ownership(struct scsi_device *sdev) | ||
366 | { | 385 | { |
367 | int err; | 386 | int err; |
368 | struct c9_inquiry *inqp; | 387 | struct c9_inquiry *inqp; |
369 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
370 | 388 | ||
371 | err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry)); | 389 | err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); |
372 | if (err == SCSI_DH_OK) { | 390 | if (err == SCSI_DH_OK) { |
373 | err = RDAC_UNOWNED; | ||
374 | inqp = &h->inq.c9; | 391 | inqp = &h->inq.c9; |
375 | /* | 392 | if ((inqp->avte_cvp >> 7) == 0x1) { |
376 | * If in AVT mode or if the path already owns the LUN, | 393 | /* LUN in AVT mode */ |
377 | * return RDAC_OWNED; | 394 | sdev_printk(KERN_NOTICE, sdev, |
378 | */ | 395 | "%s: AVT mode detected\n", |
379 | if (((inqp->avte_cvp >> 7) == 0x1) || | 396 | RDAC_NAME); |
380 | ((inqp->avte_cvp & 0x1) != 0)) | 397 | h->lun_state = RDAC_LUN_AVT; |
381 | err = RDAC_OWNED; | 398 | } else if ((inqp->avte_cvp & 0x1) != 0) { |
382 | } else | 399 | /* LUN was owned by the controller */ |
383 | err = RDAC_FAILED; | 400 | h->lun_state = RDAC_LUN_OWNED; |
401 | } | ||
402 | } | ||
403 | |||
384 | return err; | 404 | return err; |
385 | } | 405 | } |
386 | 406 | ||
387 | static int initialize_controller(struct scsi_device *sdev) | 407 | static int initialize_controller(struct scsi_device *sdev, |
408 | struct rdac_dh_data *h) | ||
388 | { | 409 | { |
389 | int err; | 410 | int err; |
390 | struct c4_inquiry *inqp; | 411 | struct c4_inquiry *inqp; |
391 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
392 | 412 | ||
393 | err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry)); | 413 | err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h); |
394 | if (err == SCSI_DH_OK) { | 414 | if (err == SCSI_DH_OK) { |
395 | inqp = &h->inq.c4; | 415 | inqp = &h->inq.c4; |
396 | h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); | 416 | h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); |
@@ -400,13 +420,12 @@ static int initialize_controller(struct scsi_device *sdev) | |||
400 | return err; | 420 | return err; |
401 | } | 421 | } |
402 | 422 | ||
403 | static int set_mode_select(struct scsi_device *sdev) | 423 | static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) |
404 | { | 424 | { |
405 | int err; | 425 | int err; |
406 | struct c2_inquiry *inqp; | 426 | struct c2_inquiry *inqp; |
407 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
408 | 427 | ||
409 | err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry)); | 428 | err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h); |
410 | if (err == SCSI_DH_OK) { | 429 | if (err == SCSI_DH_OK) { |
411 | inqp = &h->inq.c2; | 430 | inqp = &h->inq.c2; |
412 | /* | 431 | /* |
@@ -421,13 +440,13 @@ static int set_mode_select(struct scsi_device *sdev) | |||
421 | return err; | 440 | return err; |
422 | } | 441 | } |
423 | 442 | ||
424 | static int mode_select_handle_sense(struct scsi_device *sdev) | 443 | static int mode_select_handle_sense(struct scsi_device *sdev, |
444 | unsigned char *sensebuf) | ||
425 | { | 445 | { |
426 | struct scsi_sense_hdr sense_hdr; | 446 | struct scsi_sense_hdr sense_hdr; |
427 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
428 | int sense, err = SCSI_DH_IO, ret; | 447 | int sense, err = SCSI_DH_IO, ret; |
429 | 448 | ||
430 | ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); | 449 | ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); |
431 | if (!ret) | 450 | if (!ret) |
432 | goto done; | 451 | goto done; |
433 | 452 | ||
@@ -451,14 +470,13 @@ done: | |||
451 | return err; | 470 | return err; |
452 | } | 471 | } |
453 | 472 | ||
454 | static int send_mode_select(struct scsi_device *sdev) | 473 | static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) |
455 | { | 474 | { |
456 | struct request *rq; | 475 | struct request *rq; |
457 | struct request_queue *q = sdev->request_queue; | 476 | struct request_queue *q = sdev->request_queue; |
458 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
459 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | 477 | int err = SCSI_DH_RES_TEMP_UNAVAIL; |
460 | 478 | ||
461 | rq = rdac_failover_get(sdev); | 479 | rq = rdac_failover_get(sdev, h); |
462 | if (!rq) | 480 | if (!rq) |
463 | goto done; | 481 | goto done; |
464 | 482 | ||
@@ -466,9 +484,11 @@ static int send_mode_select(struct scsi_device *sdev) | |||
466 | 484 | ||
467 | err = blk_execute_rq(q, NULL, rq, 1); | 485 | err = blk_execute_rq(q, NULL, rq, 1); |
468 | if (err != SCSI_DH_OK) | 486 | if (err != SCSI_DH_OK) |
469 | err = mode_select_handle_sense(sdev); | 487 | err = mode_select_handle_sense(sdev, h->sense); |
470 | if (err == SCSI_DH_OK) | 488 | if (err == SCSI_DH_OK) |
471 | h->state = RDAC_STATE_ACTIVE; | 489 | h->state = RDAC_STATE_ACTIVE; |
490 | |||
491 | blk_put_request(rq); | ||
472 | done: | 492 | done: |
473 | return err; | 493 | return err; |
474 | } | 494 | } |
@@ -478,38 +498,23 @@ static int rdac_activate(struct scsi_device *sdev) | |||
478 | struct rdac_dh_data *h = get_rdac_data(sdev); | 498 | struct rdac_dh_data *h = get_rdac_data(sdev); |
479 | int err = SCSI_DH_OK; | 499 | int err = SCSI_DH_OK; |
480 | 500 | ||
481 | if (h->lun == UNINITIALIZED_LUN) { | 501 | err = check_ownership(sdev, h); |
482 | err = get_lun(sdev); | 502 | if (err != SCSI_DH_OK) |
483 | if (err != SCSI_DH_OK) | ||
484 | goto done; | ||
485 | } | ||
486 | |||
487 | err = check_ownership(sdev); | ||
488 | switch (err) { | ||
489 | case RDAC_UNOWNED: | ||
490 | break; | ||
491 | case RDAC_OWNED: | ||
492 | err = SCSI_DH_OK; | ||
493 | goto done; | ||
494 | case RDAC_FAILED: | ||
495 | default: | ||
496 | err = SCSI_DH_IO; | ||
497 | goto done; | 503 | goto done; |
498 | } | ||
499 | 504 | ||
500 | if (!h->ctlr) { | 505 | if (!h->ctlr) { |
501 | err = initialize_controller(sdev); | 506 | err = initialize_controller(sdev, h); |
502 | if (err != SCSI_DH_OK) | 507 | if (err != SCSI_DH_OK) |
503 | goto done; | 508 | goto done; |
504 | } | 509 | } |
505 | 510 | ||
506 | if (h->ctlr->use_ms10 == -1) { | 511 | if (h->ctlr->use_ms10 == -1) { |
507 | err = set_mode_select(sdev); | 512 | err = set_mode_select(sdev, h); |
508 | if (err != SCSI_DH_OK) | 513 | if (err != SCSI_DH_OK) |
509 | goto done; | 514 | goto done; |
510 | } | 515 | } |
511 | 516 | if (h->lun_state == RDAC_LUN_UNOWNED) | |
512 | err = send_mode_select(sdev); | 517 | err = send_mode_select(sdev, h); |
513 | done: | 518 | done: |
514 | return err; | 519 | return err; |
515 | } | 520 | } |
@@ -606,11 +611,12 @@ static int rdac_bus_attach(struct scsi_device *sdev) | |||
606 | struct scsi_dh_data *scsi_dh_data; | 611 | struct scsi_dh_data *scsi_dh_data; |
607 | struct rdac_dh_data *h; | 612 | struct rdac_dh_data *h; |
608 | unsigned long flags; | 613 | unsigned long flags; |
614 | int err; | ||
609 | 615 | ||
610 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | 616 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
611 | + sizeof(*h) , GFP_KERNEL); | 617 | + sizeof(*h) , GFP_KERNEL); |
612 | if (!scsi_dh_data) { | 618 | if (!scsi_dh_data) { |
613 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | 619 | sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", |
614 | RDAC_NAME); | 620 | RDAC_NAME); |
615 | return 0; | 621 | return 0; |
616 | } | 622 | } |
@@ -619,14 +625,33 @@ static int rdac_bus_attach(struct scsi_device *sdev) | |||
619 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | 625 | h = (struct rdac_dh_data *) scsi_dh_data->buf; |
620 | h->lun = UNINITIALIZED_LUN; | 626 | h->lun = UNINITIALIZED_LUN; |
621 | h->state = RDAC_STATE_ACTIVE; | 627 | h->state = RDAC_STATE_ACTIVE; |
628 | |||
629 | err = get_lun(sdev, h); | ||
630 | if (err != SCSI_DH_OK) | ||
631 | goto failed; | ||
632 | |||
633 | err = check_ownership(sdev, h); | ||
634 | if (err != SCSI_DH_OK) | ||
635 | goto failed; | ||
636 | |||
637 | if (!try_module_get(THIS_MODULE)) | ||
638 | goto failed; | ||
639 | |||
622 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 640 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
623 | sdev->scsi_dh_data = scsi_dh_data; | 641 | sdev->scsi_dh_data = scsi_dh_data; |
624 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | 642 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); |
625 | try_module_get(THIS_MODULE); | ||
626 | 643 | ||
627 | sdev_printk(KERN_NOTICE, sdev, "Attached %s\n", RDAC_NAME); | 644 | sdev_printk(KERN_NOTICE, sdev, |
645 | "%s: LUN %d (%s)\n", | ||
646 | RDAC_NAME, h->lun, lun_state[(int)h->lun_state]); | ||
628 | 647 | ||
629 | return 0; | 648 | return 0; |
649 | |||
650 | failed: | ||
651 | kfree(scsi_dh_data); | ||
652 | sdev_printk(KERN_ERR, sdev, "%s: not attached\n", | ||
653 | RDAC_NAME); | ||
654 | return -EINVAL; | ||
630 | } | 655 | } |
631 | 656 | ||
632 | static void rdac_bus_detach( struct scsi_device *sdev ) | 657 | static void rdac_bus_detach( struct scsi_device *sdev ) |
@@ -645,7 +670,7 @@ static void rdac_bus_detach( struct scsi_device *sdev ) | |||
645 | kref_put(&h->ctlr->kref, release_controller); | 670 | kref_put(&h->ctlr->kref, release_controller); |
646 | kfree(scsi_dh_data); | 671 | kfree(scsi_dh_data); |
647 | module_put(THIS_MODULE); | 672 | module_put(THIS_MODULE); |
648 | sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", RDAC_NAME); | 673 | sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME); |
649 | } | 674 | } |
650 | 675 | ||
651 | 676 | ||