diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-11-17 20:59:52 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 14:55:42 -0500 |
commit | b91bb296188118eea9fdc6093cfcf76bbe8589ba (patch) | |
tree | 8fe9dda8894514f9cd1184368eab975583c12f3c /drivers/scsi/libsas | |
parent | 87c8331fcf72e501c3a3c0cdc5c9391ec72f7cf2 (diff) |
[SCSI] libsas: use ->set_dmamode to notify lldds of NCQ parameters
sas_discover_sata() notifies lldds of sata devices twice. Once to allow
the 'identify' to be sent, and a second time to allow aic94xx (the only
libsas driver that cares about sata_dev.identify) to setup NCQ
parameters before the device becomes known to the midlayer. Replace
this double notification and intervening 'identify' with an explicit
->lldd_ata_set_dmamode notification. With this change all ata internal
commands are issued by libata, so we no longer need sas_issue_ata_cmd().
The data from the identify command only needs to be cached in one
location so ata_device.id replaces domain_device.sata_dev.identify.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 324 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 5 |
2 files changed, 20 insertions, 309 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 4b6365c6410f..71af919b856c 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -367,6 +367,17 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc) | |||
367 | } | 367 | } |
368 | } | 368 | } |
369 | 369 | ||
370 | |||
371 | static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev) | ||
372 | { | ||
373 | struct domain_device *dev = ap->private_data; | ||
374 | struct sas_internal *i = | ||
375 | to_sas_internal(dev->port->ha->core.shost->transportt); | ||
376 | |||
377 | if (i->dft->lldd_ata_set_dmamode) | ||
378 | i->dft->lldd_ata_set_dmamode(dev); | ||
379 | } | ||
380 | |||
370 | static struct ata_port_operations sas_sata_ops = { | 381 | static struct ata_port_operations sas_sata_ops = { |
371 | .prereset = ata_std_prereset, | 382 | .prereset = ata_std_prereset, |
372 | .softreset = sas_ata_soft_reset, | 383 | .softreset = sas_ata_soft_reset, |
@@ -380,6 +391,7 @@ static struct ata_port_operations sas_sata_ops = { | |||
380 | .qc_fill_rtf = sas_ata_qc_fill_rtf, | 391 | .qc_fill_rtf = sas_ata_qc_fill_rtf, |
381 | .port_start = ata_sas_port_start, | 392 | .port_start = ata_sas_port_start, |
382 | .port_stop = ata_sas_port_stop, | 393 | .port_stop = ata_sas_port_stop, |
394 | .set_dmamode = sas_ata_set_dmamode, | ||
383 | }; | 395 | }; |
384 | 396 | ||
385 | static struct ata_port_info sata_port_info = { | 397 | static struct ata_port_info sata_port_info = { |
@@ -442,163 +454,6 @@ void sas_ata_task_abort(struct sas_task *task) | |||
442 | complete(waiting); | 454 | complete(waiting); |
443 | } | 455 | } |
444 | 456 | ||
445 | static void sas_task_timedout(unsigned long _task) | ||
446 | { | ||
447 | struct sas_task *task = (void *) _task; | ||
448 | unsigned long flags; | ||
449 | |||
450 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
451 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
452 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
453 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
454 | |||
455 | complete(&task->completion); | ||
456 | } | ||
457 | |||
458 | static void sas_disc_task_done(struct sas_task *task) | ||
459 | { | ||
460 | if (!del_timer(&task->timer)) | ||
461 | return; | ||
462 | complete(&task->completion); | ||
463 | } | ||
464 | |||
465 | #define SAS_DEV_TIMEOUT 10 | ||
466 | |||
467 | /** | ||
468 | * sas_execute_task -- Basic task processing for discovery | ||
469 | * @task: the task to be executed | ||
470 | * @buffer: pointer to buffer to do I/O | ||
471 | * @size: size of @buffer | ||
472 | * @dma_dir: DMA direction. DMA_xxx | ||
473 | */ | ||
474 | static int sas_execute_task(struct sas_task *task, void *buffer, int size, | ||
475 | enum dma_data_direction dma_dir) | ||
476 | { | ||
477 | int res = 0; | ||
478 | struct scatterlist *scatter = NULL; | ||
479 | struct task_status_struct *ts = &task->task_status; | ||
480 | int num_scatter = 0; | ||
481 | int retries = 0; | ||
482 | struct sas_internal *i = | ||
483 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | ||
484 | |||
485 | if (dma_dir != DMA_NONE) { | ||
486 | scatter = kzalloc(sizeof(*scatter), GFP_KERNEL); | ||
487 | if (!scatter) | ||
488 | goto out; | ||
489 | |||
490 | sg_init_one(scatter, buffer, size); | ||
491 | num_scatter = 1; | ||
492 | } | ||
493 | |||
494 | task->task_proto = task->dev->tproto; | ||
495 | task->scatter = scatter; | ||
496 | task->num_scatter = num_scatter; | ||
497 | task->total_xfer_len = size; | ||
498 | task->data_dir = dma_dir; | ||
499 | task->task_done = sas_disc_task_done; | ||
500 | if (dma_dir != DMA_NONE && | ||
501 | sas_protocol_ata(task->task_proto)) { | ||
502 | task->num_scatter = dma_map_sg(task->dev->port->ha->dev, | ||
503 | task->scatter, | ||
504 | task->num_scatter, | ||
505 | task->data_dir); | ||
506 | } | ||
507 | |||
508 | for (retries = 0; retries < 5; retries++) { | ||
509 | task->task_state_flags = SAS_TASK_STATE_PENDING; | ||
510 | init_completion(&task->completion); | ||
511 | |||
512 | task->timer.data = (unsigned long) task; | ||
513 | task->timer.function = sas_task_timedout; | ||
514 | task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ; | ||
515 | add_timer(&task->timer); | ||
516 | |||
517 | res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); | ||
518 | if (res) { | ||
519 | del_timer(&task->timer); | ||
520 | SAS_DPRINTK("executing SAS discovery task failed:%d\n", | ||
521 | res); | ||
522 | goto ex_err; | ||
523 | } | ||
524 | wait_for_completion(&task->completion); | ||
525 | res = -ECOMM; | ||
526 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | ||
527 | int res2; | ||
528 | SAS_DPRINTK("task aborted, flags:0x%x\n", | ||
529 | task->task_state_flags); | ||
530 | res2 = i->dft->lldd_abort_task(task); | ||
531 | SAS_DPRINTK("came back from abort task\n"); | ||
532 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { | ||
533 | if (res2 == TMF_RESP_FUNC_COMPLETE) | ||
534 | continue; /* Retry the task */ | ||
535 | else | ||
536 | goto ex_err; | ||
537 | } | ||
538 | } | ||
539 | if (task->task_status.stat == SAM_STAT_BUSY || | ||
540 | task->task_status.stat == SAM_STAT_TASK_SET_FULL || | ||
541 | task->task_status.stat == SAS_QUEUE_FULL) { | ||
542 | SAS_DPRINTK("task: q busy, sleeping...\n"); | ||
543 | schedule_timeout_interruptible(HZ); | ||
544 | } else if (task->task_status.stat == SAM_STAT_CHECK_CONDITION) { | ||
545 | struct scsi_sense_hdr shdr; | ||
546 | |||
547 | if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size, | ||
548 | &shdr)) { | ||
549 | SAS_DPRINTK("couldn't normalize sense\n"); | ||
550 | continue; | ||
551 | } | ||
552 | if ((shdr.sense_key == 6 && shdr.asc == 0x29) || | ||
553 | (shdr.sense_key == 2 && shdr.asc == 4 && | ||
554 | shdr.ascq == 1)) { | ||
555 | SAS_DPRINTK("device %016llx LUN: %016llx " | ||
556 | "powering up or not ready yet, " | ||
557 | "sleeping...\n", | ||
558 | SAS_ADDR(task->dev->sas_addr), | ||
559 | SAS_ADDR(task->ssp_task.LUN)); | ||
560 | |||
561 | schedule_timeout_interruptible(5*HZ); | ||
562 | } else if (shdr.sense_key == 1) { | ||
563 | res = 0; | ||
564 | break; | ||
565 | } else if (shdr.sense_key == 5) { | ||
566 | break; | ||
567 | } else { | ||
568 | SAS_DPRINTK("dev %016llx LUN: %016llx " | ||
569 | "sense key:0x%x ASC:0x%x ASCQ:0x%x" | ||
570 | "\n", | ||
571 | SAS_ADDR(task->dev->sas_addr), | ||
572 | SAS_ADDR(task->ssp_task.LUN), | ||
573 | shdr.sense_key, | ||
574 | shdr.asc, shdr.ascq); | ||
575 | } | ||
576 | } else if (task->task_status.resp != SAS_TASK_COMPLETE || | ||
577 | task->task_status.stat != SAM_STAT_GOOD) { | ||
578 | SAS_DPRINTK("task finished with resp:0x%x, " | ||
579 | "stat:0x%x\n", | ||
580 | task->task_status.resp, | ||
581 | task->task_status.stat); | ||
582 | goto ex_err; | ||
583 | } else { | ||
584 | res = 0; | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | ex_err: | ||
589 | if (dma_dir != DMA_NONE) { | ||
590 | if (sas_protocol_ata(task->task_proto)) | ||
591 | dma_unmap_sg(task->dev->port->ha->dev, | ||
592 | task->scatter, task->num_scatter, | ||
593 | task->data_dir); | ||
594 | kfree(scatter); | ||
595 | } | ||
596 | out: | ||
597 | return res; | ||
598 | } | ||
599 | |||
600 | /* ---------- SATA ---------- */ | ||
601 | |||
602 | static void sas_get_ata_command_set(struct domain_device *dev) | 457 | static void sas_get_ata_command_set(struct domain_device *dev) |
603 | { | 458 | { |
604 | struct dev_to_host_fis *fis = | 459 | struct dev_to_host_fis *fis = |
@@ -642,122 +497,6 @@ static void sas_get_ata_command_set(struct domain_device *dev) | |||
642 | dev->sata_dev.command_set = ATAPI_COMMAND_SET; | 497 | dev->sata_dev.command_set = ATAPI_COMMAND_SET; |
643 | } | 498 | } |
644 | 499 | ||
645 | /** | ||
646 | * sas_issue_ata_cmd -- Basic SATA command processing for discovery | ||
647 | * @dev: the device to send the command to | ||
648 | * @command: the command register | ||
649 | * @features: the features register | ||
650 | * @buffer: pointer to buffer to do I/O | ||
651 | * @size: size of @buffer | ||
652 | * @dma_dir: DMA direction. DMA_xxx | ||
653 | */ | ||
654 | static int sas_issue_ata_cmd(struct domain_device *dev, u8 command, | ||
655 | u8 features, void *buffer, int size, | ||
656 | enum dma_data_direction dma_dir) | ||
657 | { | ||
658 | int res = 0; | ||
659 | struct sas_task *task; | ||
660 | struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *) | ||
661 | &dev->frame_rcvd[0]; | ||
662 | |||
663 | res = -ENOMEM; | ||
664 | task = sas_alloc_task(GFP_KERNEL); | ||
665 | if (!task) | ||
666 | goto out; | ||
667 | |||
668 | task->dev = dev; | ||
669 | |||
670 | task->ata_task.fis.fis_type = 0x27; | ||
671 | task->ata_task.fis.command = command; | ||
672 | task->ata_task.fis.features = features; | ||
673 | task->ata_task.fis.device = d2h_fis->device; | ||
674 | task->ata_task.retry_count = 1; | ||
675 | |||
676 | res = sas_execute_task(task, buffer, size, dma_dir); | ||
677 | |||
678 | sas_free_task(task); | ||
679 | out: | ||
680 | return res; | ||
681 | } | ||
682 | |||
683 | #define ATA_IDENTIFY_DEV 0xEC | ||
684 | #define ATA_IDENTIFY_PACKET_DEV 0xA1 | ||
685 | #define ATA_SET_FEATURES 0xEF | ||
686 | #define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07 | ||
687 | |||
688 | /** | ||
689 | * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV) | ||
690 | * @dev: STP/SATA device of interest (ATA/ATAPI) | ||
691 | * | ||
692 | * The LLDD has already been notified of this device, so that we can | ||
693 | * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY | ||
694 | * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its | ||
695 | * performance for this device. | ||
696 | */ | ||
697 | static int sas_discover_sata_dev(struct domain_device *dev) | ||
698 | { | ||
699 | int res; | ||
700 | __le16 *identify_x; | ||
701 | u8 command; | ||
702 | |||
703 | identify_x = kzalloc(512, GFP_KERNEL); | ||
704 | if (!identify_x) | ||
705 | return -ENOMEM; | ||
706 | |||
707 | if (dev->sata_dev.command_set == ATA_COMMAND_SET) { | ||
708 | dev->sata_dev.identify_device = identify_x; | ||
709 | command = ATA_IDENTIFY_DEV; | ||
710 | } else { | ||
711 | dev->sata_dev.identify_packet_device = identify_x; | ||
712 | command = ATA_IDENTIFY_PACKET_DEV; | ||
713 | } | ||
714 | |||
715 | res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512, | ||
716 | DMA_FROM_DEVICE); | ||
717 | if (res) | ||
718 | goto out_err; | ||
719 | |||
720 | /* lives on the media? */ | ||
721 | if (le16_to_cpu(identify_x[0]) & 4) { | ||
722 | /* incomplete response */ | ||
723 | SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to " | ||
724 | "dev %llx\n", SAS_ADDR(dev->sas_addr)); | ||
725 | if (!(identify_x[83] & cpu_to_le16(1<<6))) | ||
726 | goto cont1; | ||
727 | res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES, | ||
728 | ATA_FEATURE_PUP_STBY_SPIN_UP, | ||
729 | NULL, 0, DMA_NONE); | ||
730 | if (res) | ||
731 | goto cont1; | ||
732 | |||
733 | schedule_timeout_interruptible(5*HZ); /* More time? */ | ||
734 | res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512, | ||
735 | DMA_FROM_DEVICE); | ||
736 | if (res) | ||
737 | goto out_err; | ||
738 | } | ||
739 | cont1: | ||
740 | /* XXX Hint: register this SATA device with SATL. | ||
741 | When this returns, dev->sata_dev->lu is alive and | ||
742 | present. | ||
743 | sas_satl_register_dev(dev); | ||
744 | */ | ||
745 | |||
746 | sas_fill_in_rphy(dev, dev->rphy); | ||
747 | |||
748 | return 0; | ||
749 | out_err: | ||
750 | dev->sata_dev.identify_packet_device = NULL; | ||
751 | dev->sata_dev.identify_device = NULL; | ||
752 | kfree(identify_x); | ||
753 | return res; | ||
754 | } | ||
755 | |||
756 | static int sas_discover_sata_pm(struct domain_device *dev) | ||
757 | { | ||
758 | return -ENODEV; | ||
759 | } | ||
760 | |||
761 | void sas_probe_sata(struct work_struct *work) | 500 | void sas_probe_sata(struct work_struct *work) |
762 | { | 501 | { |
763 | struct domain_device *dev, *n; | 502 | struct domain_device *dev, *n; |
@@ -791,49 +530,26 @@ void sas_probe_sata(struct work_struct *work) | |||
791 | * sas_discover_sata -- discover an STP/SATA domain device | 530 | * sas_discover_sata -- discover an STP/SATA domain device |
792 | * @dev: pointer to struct domain_device of interest | 531 | * @dev: pointer to struct domain_device of interest |
793 | * | 532 | * |
794 | * First we notify the LLDD of this device, so we can send frames to | 533 | * Devices directly attached to a HA port, have no parents. All other |
795 | * it. Then depending on the type of device we call the appropriate | 534 | * devices do, and should have their "parent" pointer set appropriately |
796 | * discover functions. Once device discover is done, we notify the | 535 | * before calling this function. |
797 | * LLDD so that it can fine-tune its parameters for the device, by | ||
798 | * removing it and then adding it. That is, the second time around, | ||
799 | * the driver would have certain fields, that it is looking at, set. | ||
800 | * Finally we initialize the kobj so that the device can be added to | ||
801 | * the system at registration time. Devices directly attached to a HA | ||
802 | * port, have no parents. All other devices do, and should have their | ||
803 | * "parent" pointer set appropriately before calling this function. | ||
804 | */ | 536 | */ |
805 | int sas_discover_sata(struct domain_device *dev) | 537 | int sas_discover_sata(struct domain_device *dev) |
806 | { | 538 | { |
807 | int res; | 539 | int res; |
808 | 540 | ||
809 | sas_get_ata_command_set(dev); | 541 | if (dev->dev_type == SATA_PM) |
810 | 542 | return -ENODEV; | |
811 | res = sas_notify_lldd_dev_found(dev); | ||
812 | if (res) | ||
813 | return res; | ||
814 | |||
815 | switch (dev->dev_type) { | ||
816 | case SATA_DEV: | ||
817 | res = sas_discover_sata_dev(dev); | ||
818 | break; | ||
819 | case SATA_PM: | ||
820 | res = sas_discover_sata_pm(dev); | ||
821 | break; | ||
822 | default: | ||
823 | break; | ||
824 | } | ||
825 | sas_notify_lldd_dev_gone(dev); | ||
826 | 543 | ||
827 | if (res) | 544 | sas_get_ata_command_set(dev); |
828 | return res; | 545 | sas_fill_in_rphy(dev, dev->rphy); |
829 | 546 | ||
830 | res = sas_notify_lldd_dev_found(dev); | 547 | res = sas_notify_lldd_dev_found(dev); |
831 | if (res) | 548 | if (res) |
832 | return res; | 549 | return res; |
833 | 550 | ||
834 | sas_discover_event(dev->port, DISCE_PROBE); | 551 | sas_discover_event(dev->port, DISCE_PROBE); |
835 | 552 | return 0; | |
836 | return res; | ||
837 | } | 553 | } |
838 | 554 | ||
839 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | 555 | void sas_ata_strategy_handler(struct Scsi_Host *shost) |
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 7e8fdcb202b7..bad5eba4a92b 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -237,11 +237,6 @@ void sas_free_device(struct kref *kref) | |||
237 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) | 237 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) |
238 | kfree(dev->ex_dev.ex_phy); | 238 | kfree(dev->ex_dev.ex_phy); |
239 | 239 | ||
240 | if (dev_is_sata(dev)) { | ||
241 | kfree(dev->sata_dev.identify_device); | ||
242 | kfree(dev->sata_dev.identify_packet_device); | ||
243 | } | ||
244 | |||
245 | kfree(dev); | 240 | kfree(dev); |
246 | } | 241 | } |
247 | 242 | ||