diff options
author | David Howells <dhowells@redhat.com> | 2006-12-06 10:01:18 -0500 |
---|---|---|
committer | David Howells <dhowells@warthog.cambridge.redhat.com> | 2006-12-06 10:01:18 -0500 |
commit | 4796b71fbb907ce6b8a9acf1852d3646a80b4576 (patch) | |
tree | 6263f165446c581efdbb760205c1f85378fe6259 /drivers/scsi/libsas | |
parent | 6d5aefb8eaa38e44b5b8cf60c812aceafc02d924 (diff) | |
parent | ec0bf39a471bf6fcd01def2bd677128cea940b73 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
drivers/pcmcia/ds.c
Fix up merge failures with Linus's head and fix new compile failures.
Signed-Off-By: David Howells <dhowells@redhat.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 36 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 4 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 90 |
3 files changed, 113 insertions, 17 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index e34a93435497..d31e6fa466f7 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -597,10 +597,15 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
597 | child->iproto = phy->attached_iproto; | 597 | child->iproto = phy->attached_iproto; |
598 | memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); | 598 | memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); |
599 | sas_hash_addr(child->hashed_sas_addr, child->sas_addr); | 599 | sas_hash_addr(child->hashed_sas_addr, child->sas_addr); |
600 | phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); | 600 | if (!phy->port) { |
601 | BUG_ON(!phy->port); | 601 | phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); |
602 | /* FIXME: better error handling*/ | 602 | if (unlikely(!phy->port)) |
603 | BUG_ON(sas_port_add(phy->port) != 0); | 603 | goto out_err; |
604 | if (unlikely(sas_port_add(phy->port) != 0)) { | ||
605 | sas_port_free(phy->port); | ||
606 | goto out_err; | ||
607 | } | ||
608 | } | ||
604 | sas_ex_get_linkrate(parent, child, phy); | 609 | sas_ex_get_linkrate(parent, child, phy); |
605 | 610 | ||
606 | if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { | 611 | if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { |
@@ -615,8 +620,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
615 | SAS_DPRINTK("report phy sata to %016llx:0x%x returned " | 620 | SAS_DPRINTK("report phy sata to %016llx:0x%x returned " |
616 | "0x%x\n", SAS_ADDR(parent->sas_addr), | 621 | "0x%x\n", SAS_ADDR(parent->sas_addr), |
617 | phy_id, res); | 622 | phy_id, res); |
618 | kfree(child); | 623 | goto out_free; |
619 | return NULL; | ||
620 | } | 624 | } |
621 | memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, | 625 | memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, |
622 | sizeof(struct dev_to_host_fis)); | 626 | sizeof(struct dev_to_host_fis)); |
@@ -627,14 +631,14 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
627 | "%016llx:0x%x returned 0x%x\n", | 631 | "%016llx:0x%x returned 0x%x\n", |
628 | SAS_ADDR(child->sas_addr), | 632 | SAS_ADDR(child->sas_addr), |
629 | SAS_ADDR(parent->sas_addr), phy_id, res); | 633 | SAS_ADDR(parent->sas_addr), phy_id, res); |
630 | kfree(child); | 634 | goto out_free; |
631 | return NULL; | ||
632 | } | 635 | } |
633 | } else if (phy->attached_tproto & SAS_PROTO_SSP) { | 636 | } else if (phy->attached_tproto & SAS_PROTO_SSP) { |
634 | child->dev_type = SAS_END_DEV; | 637 | child->dev_type = SAS_END_DEV; |
635 | rphy = sas_end_device_alloc(phy->port); | 638 | rphy = sas_end_device_alloc(phy->port); |
636 | /* FIXME: error handling */ | 639 | /* FIXME: error handling */ |
637 | BUG_ON(!rphy); | 640 | if (unlikely(!rphy)) |
641 | goto out_free; | ||
638 | child->tproto = phy->attached_tproto; | 642 | child->tproto = phy->attached_tproto; |
639 | sas_init_dev(child); | 643 | sas_init_dev(child); |
640 | 644 | ||
@@ -651,9 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
651 | "at %016llx:0x%x returned 0x%x\n", | 655 | "at %016llx:0x%x returned 0x%x\n", |
652 | SAS_ADDR(child->sas_addr), | 656 | SAS_ADDR(child->sas_addr), |
653 | SAS_ADDR(parent->sas_addr), phy_id, res); | 657 | SAS_ADDR(parent->sas_addr), phy_id, res); |
654 | /* FIXME: this kfrees list elements without removing them */ | 658 | goto out_list_del; |
655 | //kfree(child); | ||
656 | return NULL; | ||
657 | } | 659 | } |
658 | } else { | 660 | } else { |
659 | SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", | 661 | SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", |
@@ -663,6 +665,16 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
663 | 665 | ||
664 | list_add_tail(&child->siblings, &parent_ex->children); | 666 | list_add_tail(&child->siblings, &parent_ex->children); |
665 | return child; | 667 | return child; |
668 | |||
669 | out_list_del: | ||
670 | list_del(&child->dev_list_node); | ||
671 | sas_rphy_free(rphy); | ||
672 | out_free: | ||
673 | sas_port_delete(phy->port); | ||
674 | out_err: | ||
675 | phy->port = NULL; | ||
676 | kfree(child); | ||
677 | return NULL; | ||
666 | } | 678 | } |
667 | 679 | ||
668 | static struct domain_device *sas_ex_discover_expander( | 680 | static struct domain_device *sas_ex_discover_expander( |
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 7b4e9169f44d..d65bc4e0f214 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -114,6 +114,8 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) | |||
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | INIT_LIST_HEAD(&sas_ha->eh_done_q); | ||
118 | |||
117 | return 0; | 119 | return 0; |
118 | 120 | ||
119 | Undo_ports: | 121 | Undo_ports: |
@@ -144,7 +146,7 @@ static int sas_get_linkerrors(struct sas_phy *phy) | |||
144 | return sas_smp_get_phy_events(phy); | 146 | return sas_smp_get_phy_events(phy); |
145 | } | 147 | } |
146 | 148 | ||
147 | static int sas_phy_reset(struct sas_phy *phy, int hard_reset) | 149 | int sas_phy_reset(struct sas_phy *phy, int hard_reset) |
148 | { | 150 | { |
149 | int ret; | 151 | int ret; |
150 | enum phy_func reset_type; | 152 | enum phy_func reset_type; |
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index e46e79355b77..e064aac06b90 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -29,9 +29,11 @@ | |||
29 | #include <scsi/scsi_device.h> | 29 | #include <scsi/scsi_device.h> |
30 | #include <scsi/scsi_tcq.h> | 30 | #include <scsi/scsi_tcq.h> |
31 | #include <scsi/scsi.h> | 31 | #include <scsi/scsi.h> |
32 | #include <scsi/scsi_eh.h> | ||
32 | #include <scsi/scsi_transport.h> | 33 | #include <scsi/scsi_transport.h> |
33 | #include <scsi/scsi_transport_sas.h> | 34 | #include <scsi/scsi_transport_sas.h> |
34 | #include "../scsi_sas_internal.h" | 35 | #include "../scsi_sas_internal.h" |
36 | #include "../scsi_transport_api.h" | ||
35 | 37 | ||
36 | #include <linux/err.h> | 38 | #include <linux/err.h> |
37 | #include <linux/blkdev.h> | 39 | #include <linux/blkdev.h> |
@@ -46,6 +48,7 @@ static void sas_scsi_task_done(struct sas_task *task) | |||
46 | { | 48 | { |
47 | struct task_status_struct *ts = &task->task_status; | 49 | struct task_status_struct *ts = &task->task_status; |
48 | struct scsi_cmnd *sc = task->uldd_task; | 50 | struct scsi_cmnd *sc = task->uldd_task; |
51 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host); | ||
49 | unsigned ts_flags = task->task_state_flags; | 52 | unsigned ts_flags = task->task_state_flags; |
50 | int hs = 0, stat = 0; | 53 | int hs = 0, stat = 0; |
51 | 54 | ||
@@ -116,7 +119,7 @@ static void sas_scsi_task_done(struct sas_task *task) | |||
116 | sas_free_task(task); | 119 | sas_free_task(task); |
117 | /* This is very ugly but this is how SCSI Core works. */ | 120 | /* This is very ugly but this is how SCSI Core works. */ |
118 | if (ts_flags & SAS_TASK_STATE_ABORTED) | 121 | if (ts_flags & SAS_TASK_STATE_ABORTED) |
119 | scsi_finish_command(sc); | 122 | scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q); |
120 | else | 123 | else |
121 | sc->scsi_done(sc); | 124 | sc->scsi_done(sc); |
122 | } | 125 | } |
@@ -307,6 +310,15 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
307 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 310 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
308 | } | 311 | } |
309 | 312 | ||
313 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
314 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | ||
315 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
316 | SAS_DPRINTK("%s: task 0x%p already aborted\n", | ||
317 | __FUNCTION__, task); | ||
318 | return TASK_IS_ABORTED; | ||
319 | } | ||
320 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
321 | |||
310 | for (i = 0; i < 5; i++) { | 322 | for (i = 0; i < 5; i++) { |
311 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); | 323 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); |
312 | res = si->dft->lldd_abort_task(task); | 324 | res = si->dft->lldd_abort_task(task); |
@@ -409,13 +421,16 @@ Again: | |||
409 | SAS_DPRINTK("going over list...\n"); | 421 | SAS_DPRINTK("going over list...\n"); |
410 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | 422 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { |
411 | struct sas_task *task = TO_SAS_TASK(cmd); | 423 | struct sas_task *task = TO_SAS_TASK(cmd); |
424 | list_del_init(&cmd->eh_entry); | ||
412 | 425 | ||
426 | if (!task) { | ||
427 | SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); | ||
428 | continue; | ||
429 | } | ||
413 | SAS_DPRINTK("trying to find task 0x%p\n", task); | 430 | SAS_DPRINTK("trying to find task 0x%p\n", task); |
414 | list_del_init(&cmd->eh_entry); | ||
415 | res = sas_scsi_find_task(task); | 431 | res = sas_scsi_find_task(task); |
416 | 432 | ||
417 | cmd->eh_eflags = 0; | 433 | cmd->eh_eflags = 0; |
418 | shost->host_failed--; | ||
419 | 434 | ||
420 | switch (res) { | 435 | switch (res) { |
421 | case TASK_IS_DONE: | 436 | case TASK_IS_DONE: |
@@ -491,6 +506,7 @@ Again: | |||
491 | } | 506 | } |
492 | } | 507 | } |
493 | out: | 508 | out: |
509 | scsi_eh_flush_done_q(&ha->eh_done_q); | ||
494 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | 510 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); |
495 | return; | 511 | return; |
496 | clear_q: | 512 | clear_q: |
@@ -508,12 +524,18 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
508 | unsigned long flags; | 524 | unsigned long flags; |
509 | 525 | ||
510 | if (!task) { | 526 | if (!task) { |
511 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | 527 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", |
512 | cmd, task); | 528 | cmd, task); |
513 | return EH_HANDLED; | 529 | return EH_HANDLED; |
514 | } | 530 | } |
515 | 531 | ||
516 | spin_lock_irqsave(&task->task_state_lock, flags); | 532 | spin_lock_irqsave(&task->task_state_lock, flags); |
533 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | ||
534 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
535 | SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: " | ||
536 | "EH_NOT_HANDLED\n", cmd, task); | ||
537 | return EH_NOT_HANDLED; | ||
538 | } | ||
517 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 539 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
518 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 540 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
519 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | 541 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", |
@@ -777,6 +799,64 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) | |||
777 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 799 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
778 | } | 800 | } |
779 | 801 | ||
802 | static int do_sas_task_abort(struct sas_task *task) | ||
803 | { | ||
804 | struct scsi_cmnd *sc = task->uldd_task; | ||
805 | struct sas_internal *si = | ||
806 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | ||
807 | unsigned long flags; | ||
808 | int res; | ||
809 | |||
810 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
811 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | ||
812 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
813 | SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, | ||
814 | task); | ||
815 | return 0; | ||
816 | } | ||
817 | |||
818 | task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED; | ||
819 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
820 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
821 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
822 | |||
823 | if (!si->dft->lldd_abort_task) | ||
824 | return -ENODEV; | ||
825 | |||
826 | res = si->dft->lldd_abort_task(task); | ||
827 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || | ||
828 | (res == TMF_RESP_FUNC_COMPLETE)) | ||
829 | { | ||
830 | /* SMP commands don't have scsi_cmds(?) */ | ||
831 | if (!sc) { | ||
832 | task->task_done(task); | ||
833 | return 0; | ||
834 | } | ||
835 | scsi_req_abort_cmd(sc); | ||
836 | scsi_schedule_eh(sc->device->host); | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
841 | task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED; | ||
842 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
843 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | ||
844 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
845 | |||
846 | return -EAGAIN; | ||
847 | } | ||
848 | |||
849 | void sas_task_abort(struct sas_task *task) | ||
850 | { | ||
851 | int i; | ||
852 | |||
853 | for (i = 0; i < 5; i++) | ||
854 | if (!do_sas_task_abort(task)) | ||
855 | return; | ||
856 | |||
857 | SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); | ||
858 | } | ||
859 | |||
780 | EXPORT_SYMBOL_GPL(sas_queuecommand); | 860 | EXPORT_SYMBOL_GPL(sas_queuecommand); |
781 | EXPORT_SYMBOL_GPL(sas_target_alloc); | 861 | EXPORT_SYMBOL_GPL(sas_target_alloc); |
782 | EXPORT_SYMBOL_GPL(sas_slave_configure); | 862 | EXPORT_SYMBOL_GPL(sas_slave_configure); |
@@ -784,3 +864,5 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); | |||
784 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); | 864 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); |
785 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | 865 | EXPORT_SYMBOL_GPL(sas_change_queue_type); |
786 | EXPORT_SYMBOL_GPL(sas_bios_param); | 866 | EXPORT_SYMBOL_GPL(sas_bios_param); |
867 | EXPORT_SYMBOL_GPL(sas_task_abort); | ||
868 | EXPORT_SYMBOL_GPL(sas_phy_reset); | ||