diff options
Diffstat (limited to 'drivers/scsi/aic94xx')
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_dev.c | 16 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_dump.c | 2 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_init.c | 49 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_reg_def.h | 5 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_sas.h | 1 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_scb.c | 122 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_sds.c | 10 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_seq.c | 45 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_seq.h | 1 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_task.c | 9 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_tmf.c | 4 |
11 files changed, 164 insertions, 100 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 6f8901b748f7..c520e5b41fb5 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c | |||
@@ -37,18 +37,14 @@ | |||
37 | 37 | ||
38 | static inline int asd_get_ddb(struct asd_ha_struct *asd_ha) | 38 | static inline int asd_get_ddb(struct asd_ha_struct *asd_ha) |
39 | { | 39 | { |
40 | unsigned long flags; | ||
41 | int ddb, i; | 40 | int ddb, i; |
42 | 41 | ||
43 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
44 | ddb = FIND_FREE_DDB(asd_ha); | 42 | ddb = FIND_FREE_DDB(asd_ha); |
45 | if (ddb >= asd_ha->hw_prof.max_ddbs) { | 43 | if (ddb >= asd_ha->hw_prof.max_ddbs) { |
46 | ddb = -ENOMEM; | 44 | ddb = -ENOMEM; |
47 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
48 | goto out; | 45 | goto out; |
49 | } | 46 | } |
50 | SET_DDB(ddb, asd_ha); | 47 | SET_DDB(ddb, asd_ha); |
51 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
52 | 48 | ||
53 | for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) | 49 | for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) |
54 | asd_ddbsite_write_dword(asd_ha, ddb, i, 0); | 50 | asd_ddbsite_write_dword(asd_ha, ddb, i, 0); |
@@ -77,14 +73,10 @@ out: | |||
77 | 73 | ||
78 | static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) | 74 | static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) |
79 | { | 75 | { |
80 | unsigned long flags; | ||
81 | |||
82 | if (!ddb || ddb >= 0xFFFF) | 76 | if (!ddb || ddb >= 0xFFFF) |
83 | return; | 77 | return; |
84 | asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED); | 78 | asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED); |
85 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
86 | CLEAR_DDB(ddb, asd_ha); | 79 | CLEAR_DDB(ddb, asd_ha); |
87 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
88 | } | 80 | } |
89 | 81 | ||
90 | static inline void asd_set_ddb_type(struct domain_device *dev) | 82 | static inline void asd_set_ddb_type(struct domain_device *dev) |
@@ -320,8 +312,11 @@ out: | |||
320 | 312 | ||
321 | int asd_dev_found(struct domain_device *dev) | 313 | int asd_dev_found(struct domain_device *dev) |
322 | { | 314 | { |
315 | unsigned long flags; | ||
323 | int res = 0; | 316 | int res = 0; |
317 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
324 | 318 | ||
319 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
325 | switch (dev->dev_type) { | 320 | switch (dev->dev_type) { |
326 | case SATA_PM: | 321 | case SATA_PM: |
327 | res = asd_init_sata_pm_ddb(dev); | 322 | res = asd_init_sata_pm_ddb(dev); |
@@ -335,14 +330,18 @@ int asd_dev_found(struct domain_device *dev) | |||
335 | else | 330 | else |
336 | res = asd_init_initiator_ddb(dev); | 331 | res = asd_init_initiator_ddb(dev); |
337 | } | 332 | } |
333 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
334 | |||
338 | return res; | 335 | return res; |
339 | } | 336 | } |
340 | 337 | ||
341 | void asd_dev_gone(struct domain_device *dev) | 338 | void asd_dev_gone(struct domain_device *dev) |
342 | { | 339 | { |
343 | int ddb, sister_ddb; | 340 | int ddb, sister_ddb; |
341 | unsigned long flags; | ||
344 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | 342 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; |
345 | 343 | ||
344 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
346 | ddb = (int) (unsigned long) dev->lldd_dev; | 345 | ddb = (int) (unsigned long) dev->lldd_dev; |
347 | sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB); | 346 | sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB); |
348 | 347 | ||
@@ -350,4 +349,5 @@ void asd_dev_gone(struct domain_device *dev) | |||
350 | asd_free_ddb(asd_ha, sister_ddb); | 349 | asd_free_ddb(asd_ha, sister_ddb); |
351 | asd_free_ddb(asd_ha, ddb); | 350 | asd_free_ddb(asd_ha, ddb); |
352 | dev->lldd_dev = NULL; | 351 | dev->lldd_dev = NULL; |
352 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
353 | } | 353 | } |
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c index e6ade5996d95..6bd8e3059d27 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.c +++ b/drivers/scsi/aic94xx/aic94xx_dump.c | |||
@@ -556,7 +556,7 @@ static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq) | |||
556 | PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL); | 556 | PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL); |
557 | PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER); | 557 | PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER); |
558 | PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS); | 558 | PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS); |
559 | PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE); | 559 | PRINT_LMIP_dword(asd_ha, lseq, CONNECTION_STATE); |
560 | PRINT_LMIP_word(asd_ha, lseq, CONCTL); | 560 | PRINT_LMIP_word(asd_ha, lseq, CONCTL); |
561 | PRINT_LMIP_byte(asd_ha, lseq, CONSTAT); | 561 | PRINT_LMIP_byte(asd_ha, lseq, CONSTAT); |
562 | PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES); | 562 | PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES); |
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index fbc82b00a418..bc7744e35ad0 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include "aic94xx_seq.h" | 38 | #include "aic94xx_seq.h" |
39 | 39 | ||
40 | /* The format is "version.release.patchlevel" */ | 40 | /* The format is "version.release.patchlevel" */ |
41 | #define ASD_DRIVER_VERSION "1.0.2" | 41 | #define ASD_DRIVER_VERSION "1.0.3" |
42 | 42 | ||
43 | static int use_msi = 0; | 43 | static int use_msi = 0; |
44 | module_param_named(use_msi, use_msi, int, S_IRUGO); | 44 | module_param_named(use_msi, use_msi, int, S_IRUGO); |
@@ -57,6 +57,8 @@ MODULE_PARM_DESC(collector, "\n" | |||
57 | char sas_addr_str[2*SAS_ADDR_SIZE + 1] = ""; | 57 | char sas_addr_str[2*SAS_ADDR_SIZE + 1] = ""; |
58 | 58 | ||
59 | static struct scsi_transport_template *aic94xx_transport_template; | 59 | static struct scsi_transport_template *aic94xx_transport_template; |
60 | static int asd_scan_finished(struct Scsi_Host *, unsigned long); | ||
61 | static void asd_scan_start(struct Scsi_Host *); | ||
60 | 62 | ||
61 | static struct scsi_host_template aic94xx_sht = { | 63 | static struct scsi_host_template aic94xx_sht = { |
62 | .module = THIS_MODULE, | 64 | .module = THIS_MODULE, |
@@ -66,6 +68,8 @@ static struct scsi_host_template aic94xx_sht = { | |||
66 | .target_alloc = sas_target_alloc, | 68 | .target_alloc = sas_target_alloc, |
67 | .slave_configure = sas_slave_configure, | 69 | .slave_configure = sas_slave_configure, |
68 | .slave_destroy = sas_slave_destroy, | 70 | .slave_destroy = sas_slave_destroy, |
71 | .scan_finished = asd_scan_finished, | ||
72 | .scan_start = asd_scan_start, | ||
69 | .change_queue_depth = sas_change_queue_depth, | 73 | .change_queue_depth = sas_change_queue_depth, |
70 | .change_queue_type = sas_change_queue_type, | 74 | .change_queue_type = sas_change_queue_type, |
71 | .bios_param = sas_bios_param, | 75 | .bios_param = sas_bios_param, |
@@ -75,6 +79,8 @@ static struct scsi_host_template aic94xx_sht = { | |||
75 | .sg_tablesize = SG_ALL, | 79 | .sg_tablesize = SG_ALL, |
76 | .max_sectors = SCSI_DEFAULT_MAX_SECTORS, | 80 | .max_sectors = SCSI_DEFAULT_MAX_SECTORS, |
77 | .use_clustering = ENABLE_CLUSTERING, | 81 | .use_clustering = ENABLE_CLUSTERING, |
82 | .eh_device_reset_handler = sas_eh_device_reset_handler, | ||
83 | .eh_bus_reset_handler = sas_eh_bus_reset_handler, | ||
78 | }; | 84 | }; |
79 | 85 | ||
80 | static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha) | 86 | static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha) |
@@ -234,7 +240,7 @@ static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha) | |||
234 | } | 240 | } |
235 | /* Provide some sane default values. */ | 241 | /* Provide some sane default values. */ |
236 | asd_ha->hw_prof.max_scbs = 512; | 242 | asd_ha->hw_prof.max_scbs = 512; |
237 | asd_ha->hw_prof.max_ddbs = 128; | 243 | asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS; |
238 | asd_ha->hw_prof.num_phys = ASD_MAX_PHYS; | 244 | asd_ha->hw_prof.num_phys = ASD_MAX_PHYS; |
239 | /* All phys are enabled, by default. */ | 245 | /* All phys are enabled, by default. */ |
240 | asd_ha->hw_prof.enabled_phys = 0xFF; | 246 | asd_ha->hw_prof.enabled_phys = 0xFF; |
@@ -526,6 +532,7 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha) | |||
526 | asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; | 532 | asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; |
527 | 533 | ||
528 | asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; | 534 | asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; |
535 | asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; | ||
529 | 536 | ||
530 | return sas_register_ha(&asd_ha->sas_ha); | 537 | return sas_register_ha(&asd_ha->sas_ha); |
531 | } | 538 | } |
@@ -671,21 +678,10 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, | |||
671 | if (err) | 678 | if (err) |
672 | goto Err_reg_sas; | 679 | goto Err_reg_sas; |
673 | 680 | ||
674 | err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); | 681 | scsi_scan_host(shost); |
675 | if (err) { | ||
676 | asd_printk("coudln't enable phys, err:%d\n", err); | ||
677 | goto Err_en_phys; | ||
678 | } | ||
679 | ASD_DPRINTK("enabled phys\n"); | ||
680 | /* give the phy enabling interrupt event time to come in (1s | ||
681 | * is empirically about all it takes) */ | ||
682 | ssleep(1); | ||
683 | /* Wait for discovery to finish */ | ||
684 | scsi_flush_work(asd_ha->sas_ha.core.shost); | ||
685 | 682 | ||
686 | return 0; | 683 | return 0; |
687 | Err_en_phys: | 684 | |
688 | asd_unregister_sas_ha(asd_ha); | ||
689 | Err_reg_sas: | 685 | Err_reg_sas: |
690 | asd_remove_dev_attrs(asd_ha); | 686 | asd_remove_dev_attrs(asd_ha); |
691 | Err_dev_attrs: | 687 | Err_dev_attrs: |
@@ -778,6 +774,28 @@ static void __devexit asd_pci_remove(struct pci_dev *dev) | |||
778 | return; | 774 | return; |
779 | } | 775 | } |
780 | 776 | ||
777 | static void asd_scan_start(struct Scsi_Host *shost) | ||
778 | { | ||
779 | struct asd_ha_struct *asd_ha; | ||
780 | int err; | ||
781 | |||
782 | asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha; | ||
783 | err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); | ||
784 | if (err) | ||
785 | asd_printk("Couldn't enable phys, err:%d\n", err); | ||
786 | } | ||
787 | |||
788 | static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time) | ||
789 | { | ||
790 | /* give the phy enabling interrupt event time to come in (1s | ||
791 | * is empirically about all it takes) */ | ||
792 | if (time < HZ) | ||
793 | return 0; | ||
794 | /* Wait for discovery to finish */ | ||
795 | scsi_flush_work(shost); | ||
796 | return 1; | ||
797 | } | ||
798 | |||
781 | static ssize_t asd_version_show(struct device_driver *driver, char *buf) | 799 | static ssize_t asd_version_show(struct device_driver *driver, char *buf) |
782 | { | 800 | { |
783 | return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION); | 801 | return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION); |
@@ -885,6 +903,7 @@ static void __exit aic94xx_exit(void) | |||
885 | asd_remove_driver_attrs(&aic94xx_pci_driver.driver); | 903 | asd_remove_driver_attrs(&aic94xx_pci_driver.driver); |
886 | pci_unregister_driver(&aic94xx_pci_driver); | 904 | pci_unregister_driver(&aic94xx_pci_driver); |
887 | sas_release_transport(aic94xx_transport_template); | 905 | sas_release_transport(aic94xx_transport_template); |
906 | asd_release_firmware(); | ||
888 | asd_destroy_global_caches(); | 907 | asd_destroy_global_caches(); |
889 | asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, | 908 | asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, |
890 | ASD_DRIVER_VERSION); | 909 | ASD_DRIVER_VERSION); |
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index a11f4e6d8bd9..a43e8cdf4ee4 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h | |||
@@ -2226,9 +2226,10 @@ | |||
2226 | #define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074) | 2226 | #define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074) |
2227 | #define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075) | 2227 | #define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075) |
2228 | #define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076) | 2228 | #define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076) |
2229 | #define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A) | 2229 | #define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x0078) |
2230 | #define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007A) | ||
2230 | #define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C) | 2231 | #define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C) |
2231 | #define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E) | 2232 | #define LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E) |
2232 | 2233 | ||
2233 | /* Mode dependent scratch page 1, mode 0 and mode 1 */ | 2234 | /* Mode dependent scratch page 1, mode 0 and mode 1 */ |
2234 | #define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020) | 2235 | #define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020) |
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h index 9050e93bfd5e..fa7c5290257d 100644 --- a/drivers/scsi/aic94xx/aic94xx_sas.h +++ b/drivers/scsi/aic94xx/aic94xx_sas.h | |||
@@ -34,6 +34,7 @@ | |||
34 | * domain that this sequencer can maintain low-level connections for | 34 | * domain that this sequencer can maintain low-level connections for |
35 | * us. They are be 64 bytes. | 35 | * us. They are be 64 bytes. |
36 | */ | 36 | */ |
37 | #define ASD_MAX_DDBS 128 | ||
37 | 38 | ||
38 | struct asd_ddb_ssp_smp_target_port { | 39 | struct asd_ddb_ssp_smp_target_port { |
39 | u8 conn_type; /* byte 0 */ | 40 | u8 conn_type; /* byte 0 */ |
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 75ed6b0569d1..8f43ff772f23 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c | |||
@@ -413,40 +413,6 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id) | |||
413 | } | 413 | } |
414 | } | 414 | } |
415 | 415 | ||
416 | /* hard reset a phy later */ | ||
417 | static void do_phy_reset_later(struct work_struct *work) | ||
418 | { | ||
419 | struct sas_phy *sas_phy = | ||
420 | container_of(work, struct sas_phy, reset_work); | ||
421 | int error; | ||
422 | |||
423 | ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__, | ||
424 | sas_phy->identify.phy_identifier); | ||
425 | /* Reset device port */ | ||
426 | error = sas_phy_reset(sas_phy, 1); | ||
427 | if (error) | ||
428 | ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n", | ||
429 | __FUNCTION__, sas_phy->identify.phy_identifier, error); | ||
430 | } | ||
431 | |||
432 | static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost) | ||
433 | { | ||
434 | INIT_WORK(&sas_phy->reset_work, do_phy_reset_later); | ||
435 | queue_work(shost->work_q, &sas_phy->reset_work); | ||
436 | } | ||
437 | |||
438 | /* start up the ABORT TASK tmf... */ | ||
439 | static void task_kill_later(struct asd_ascb *ascb) | ||
440 | { | ||
441 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
442 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; | ||
443 | struct Scsi_Host *shost = sas_ha->core.shost; | ||
444 | struct sas_task *task = ascb->uldd_task; | ||
445 | |||
446 | INIT_WORK(&task->abort_work, sas_task_abort); | ||
447 | queue_work(shost->work_q, &task->abort_work); | ||
448 | } | ||
449 | |||
450 | static void escb_tasklet_complete(struct asd_ascb *ascb, | 416 | static void escb_tasklet_complete(struct asd_ascb *ascb, |
451 | struct done_list_struct *dl) | 417 | struct done_list_struct *dl) |
452 | { | 418 | { |
@@ -479,26 +445,55 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
479 | case REQ_TASK_ABORT: { | 445 | case REQ_TASK_ABORT: { |
480 | struct asd_ascb *a, *b; | 446 | struct asd_ascb *a, *b; |
481 | u16 tc_abort; | 447 | u16 tc_abort; |
448 | struct domain_device *failed_dev = NULL; | ||
449 | |||
450 | ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", | ||
451 | __FUNCTION__, dl->status_block[3]); | ||
482 | 452 | ||
453 | /* | ||
454 | * Find the task that caused the abort and abort it first. | ||
455 | * The sequencer won't put anything on the done list until | ||
456 | * that happens. | ||
457 | */ | ||
483 | tc_abort = *((u16*)(&dl->status_block[1])); | 458 | tc_abort = *((u16*)(&dl->status_block[1])); |
484 | tc_abort = le16_to_cpu(tc_abort); | 459 | tc_abort = le16_to_cpu(tc_abort); |
485 | 460 | ||
486 | ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", | 461 | list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { |
487 | __FUNCTION__, dl->status_block[3]); | 462 | struct sas_task *task = ascb->uldd_task; |
488 | 463 | ||
489 | /* Find the pending task and abort it. */ | 464 | if (task && a->tc_index == tc_abort) { |
490 | list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) | 465 | failed_dev = task->dev; |
491 | if (a->tc_index == tc_abort) { | 466 | sas_task_abort(task); |
492 | task_kill_later(a); | ||
493 | break; | 467 | break; |
494 | } | 468 | } |
469 | } | ||
470 | |||
471 | if (!failed_dev) { | ||
472 | ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n", | ||
473 | __FUNCTION__, tc_abort); | ||
474 | goto out; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Now abort everything else for that device (hba?) so | ||
479 | * that the EH will wake up and do something. | ||
480 | */ | ||
481 | list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { | ||
482 | struct sas_task *task = ascb->uldd_task; | ||
483 | |||
484 | if (task && | ||
485 | task->dev == failed_dev && | ||
486 | a->tc_index != tc_abort) | ||
487 | sas_task_abort(task); | ||
488 | } | ||
489 | |||
495 | goto out; | 490 | goto out; |
496 | } | 491 | } |
497 | case REQ_DEVICE_RESET: { | 492 | case REQ_DEVICE_RESET: { |
498 | struct Scsi_Host *shost = sas_ha->core.shost; | ||
499 | struct sas_phy *dev_phy; | ||
500 | struct asd_ascb *a; | 493 | struct asd_ascb *a; |
501 | u16 conn_handle; | 494 | u16 conn_handle; |
495 | unsigned long flags; | ||
496 | struct sas_task *last_dev_task = NULL; | ||
502 | 497 | ||
503 | conn_handle = *((u16*)(&dl->status_block[1])); | 498 | conn_handle = *((u16*)(&dl->status_block[1])); |
504 | conn_handle = le16_to_cpu(conn_handle); | 499 | conn_handle = le16_to_cpu(conn_handle); |
@@ -506,32 +501,47 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
506 | ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__, | 501 | ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__, |
507 | dl->status_block[3]); | 502 | dl->status_block[3]); |
508 | 503 | ||
509 | /* Kill all pending tasks and reset the device */ | 504 | /* Find the last pending task for the device... */ |
510 | dev_phy = NULL; | ||
511 | list_for_each_entry(a, &asd_ha->seq.pend_q, list) { | 505 | list_for_each_entry(a, &asd_ha->seq.pend_q, list) { |
512 | struct sas_task *task; | ||
513 | struct domain_device *dev; | ||
514 | u16 x; | 506 | u16 x; |
507 | struct domain_device *dev; | ||
508 | struct sas_task *task = a->uldd_task; | ||
515 | 509 | ||
516 | task = a->uldd_task; | ||
517 | if (!task) | 510 | if (!task) |
518 | continue; | 511 | continue; |
519 | dev = task->dev; | 512 | dev = task->dev; |
520 | 513 | ||
521 | x = (unsigned long)dev->lldd_dev; | 514 | x = (unsigned long)dev->lldd_dev; |
522 | if (x == conn_handle) { | 515 | if (x == conn_handle) |
523 | dev_phy = dev->port->phy; | 516 | last_dev_task = task; |
524 | task_kill_later(a); | ||
525 | } | ||
526 | } | 517 | } |
527 | 518 | ||
528 | /* Reset device port */ | 519 | if (!last_dev_task) { |
529 | if (!dev_phy) { | 520 | ASD_DPRINTK("%s: Device reset for idle device %d?\n", |
530 | ASD_DPRINTK("%s: No pending commands; can't reset.\n", | 521 | __FUNCTION__, conn_handle); |
531 | __FUNCTION__); | ||
532 | goto out; | 522 | goto out; |
533 | } | 523 | } |
534 | phy_reset_later(dev_phy, shost); | 524 | |
525 | /* ...and set the reset flag */ | ||
526 | spin_lock_irqsave(&last_dev_task->task_state_lock, flags); | ||
527 | last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; | ||
528 | spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags); | ||
529 | |||
530 | /* Kill all pending tasks for the device */ | ||
531 | list_for_each_entry(a, &asd_ha->seq.pend_q, list) { | ||
532 | u16 x; | ||
533 | struct domain_device *dev; | ||
534 | struct sas_task *task = a->uldd_task; | ||
535 | |||
536 | if (!task) | ||
537 | continue; | ||
538 | dev = task->dev; | ||
539 | |||
540 | x = (unsigned long)dev->lldd_dev; | ||
541 | if (x == conn_handle) | ||
542 | sas_task_abort(task); | ||
543 | } | ||
544 | |||
535 | goto out; | 545 | goto out; |
536 | } | 546 | } |
537 | case SIGNAL_NCQ_ERROR: | 547 | case SIGNAL_NCQ_ERROR: |
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index e5a0ec37e954..5b0932f61473 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c | |||
@@ -427,7 +427,7 @@ struct asd_manuf_sec { | |||
427 | 427 | ||
428 | struct asd_manuf_phy_desc { | 428 | struct asd_manuf_phy_desc { |
429 | u8 state; /* low 4 bits */ | 429 | u8 state; /* low 4 bits */ |
430 | #define MS_PHY_STATE_ENABLEABLE 0 | 430 | #define MS_PHY_STATE_ENABLED 0 |
431 | #define MS_PHY_STATE_REPORTED 1 | 431 | #define MS_PHY_STATE_REPORTED 1 |
432 | #define MS_PHY_STATE_HIDDEN 2 | 432 | #define MS_PHY_STATE_HIDDEN 2 |
433 | u8 phy_id; | 433 | u8 phy_id; |
@@ -756,11 +756,11 @@ static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1) | |||
756 | * | 756 | * |
757 | * HIDDEN phys do not count in the total count. REPORTED phys cannot | 757 | * HIDDEN phys do not count in the total count. REPORTED phys cannot |
758 | * be enabled but are reported and counted towards the total. | 758 | * be enabled but are reported and counted towards the total. |
759 | * ENEBLEABLE phys are enabled by default and count towards the total. | 759 | * ENABLED phys are enabled by default and count towards the total. |
760 | * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys | 760 | * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys |
761 | * merely specifies the number of phys the host adapter decided to | 761 | * merely specifies the number of phys the host adapter decided to |
762 | * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN, | 762 | * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN, |
763 | * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE. | 763 | * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENABLED. |
764 | * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2 | 764 | * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2 |
765 | * are actually enabled (enabled by default, max number of phys | 765 | * are actually enabled (enabled by default, max number of phys |
766 | * enableable in this case). | 766 | * enableable in this case). |
@@ -816,8 +816,8 @@ static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha, | |||
816 | asd_ha->hw_prof.enabled_phys &= ~(1 << i); | 816 | asd_ha->hw_prof.enabled_phys &= ~(1 << i); |
817 | rep_phys++; | 817 | rep_phys++; |
818 | continue; | 818 | continue; |
819 | case MS_PHY_STATE_ENABLEABLE: | 819 | case MS_PHY_STATE_ENABLED: |
820 | ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i); | 820 | ASD_DPRINTK("ms: phy%d: ENABLED\n", i); |
821 | asd_ha->hw_prof.enabled_phys |= (1 << i); | 821 | asd_ha->hw_prof.enabled_phys |= (1 << i); |
822 | en_phys++; | 822 | en_phys++; |
823 | break; | 823 | break; |
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index 845112539d05..eae7a247bece 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c | |||
@@ -810,6 +810,8 @@ static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) | |||
810 | /* No delay for the first NOTIFY to be sent to the attached target. */ | 810 | /* No delay for the first NOTIFY to be sent to the attached target. */ |
811 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), | 811 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), |
812 | ASD_NOTIFY_DOWN_COUNT); | 812 | ASD_NOTIFY_DOWN_COUNT); |
813 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(lseq), | ||
814 | ASD_NOTIFY_DOWN_COUNT); | ||
813 | 815 | ||
814 | /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ | 816 | /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ |
815 | for (i = 0; i < 2; i++) { | 817 | for (i = 0; i < 2; i++) { |
@@ -907,6 +909,16 @@ static void asd_init_scb_sites(struct asd_ha_struct *asd_ha) | |||
907 | for (i = 0; i < ASD_SCB_SIZE; i += 4) | 909 | for (i = 0; i < ASD_SCB_SIZE; i += 4) |
908 | asd_scbsite_write_dword(asd_ha, site_no, i, 0); | 910 | asd_scbsite_write_dword(asd_ha, site_no, i, 0); |
909 | 911 | ||
912 | /* Initialize SCB Site Opcode field to invalid. */ | ||
913 | asd_scbsite_write_byte(asd_ha, site_no, | ||
914 | offsetof(struct scb_header, opcode), | ||
915 | 0xFF); | ||
916 | |||
917 | /* Initialize SCB Site Flags field to mean a response | ||
918 | * frame has been received. This means inadvertent | ||
919 | * frames received to be dropped. */ | ||
920 | asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); | ||
921 | |||
910 | /* Workaround needed by SEQ to fix a SATA issue is to exclude | 922 | /* Workaround needed by SEQ to fix a SATA issue is to exclude |
911 | * certain SCB sites from the free list. */ | 923 | * certain SCB sites from the free list. */ |
912 | if (!SCB_SITE_VALID(site_no)) | 924 | if (!SCB_SITE_VALID(site_no)) |
@@ -922,16 +934,6 @@ static void asd_init_scb_sites(struct asd_ha_struct *asd_ha) | |||
922 | /* Q_NEXT field of the last SCB is invalidated. */ | 934 | /* Q_NEXT field of the last SCB is invalidated. */ |
923 | asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); | 935 | asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); |
924 | 936 | ||
925 | /* Initialize SCB Site Opcode field to invalid. */ | ||
926 | asd_scbsite_write_byte(asd_ha, site_no, | ||
927 | offsetof(struct scb_header, opcode), | ||
928 | 0xFF); | ||
929 | |||
930 | /* Initialize SCB Site Flags field to mean a response | ||
931 | * frame has been received. This means inadvertent | ||
932 | * frames received to be dropped. */ | ||
933 | asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); | ||
934 | |||
935 | first_scb_site_no = site_no; | 937 | first_scb_site_no = site_no; |
936 | max_scbs++; | 938 | max_scbs++; |
937 | } | 939 | } |
@@ -1173,6 +1175,16 @@ static void asd_init_ddb_0(struct asd_ha_struct *asd_ha) | |||
1173 | set_bit(0, asd_ha->hw_prof.ddb_bitmap); | 1175 | set_bit(0, asd_ha->hw_prof.ddb_bitmap); |
1174 | } | 1176 | } |
1175 | 1177 | ||
1178 | static void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha) | ||
1179 | { | ||
1180 | unsigned int i; | ||
1181 | unsigned int ddb_site; | ||
1182 | |||
1183 | for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++) | ||
1184 | for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) | ||
1185 | asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0); | ||
1186 | } | ||
1187 | |||
1176 | /** | 1188 | /** |
1177 | * asd_seq_setup_seqs -- setup and initialize central and link sequencers | 1189 | * asd_seq_setup_seqs -- setup and initialize central and link sequencers |
1178 | * @asd_ha: pointer to host adapter structure | 1190 | * @asd_ha: pointer to host adapter structure |
@@ -1182,6 +1194,9 @@ static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha) | |||
1182 | int lseq; | 1194 | int lseq; |
1183 | u8 lseq_mask; | 1195 | u8 lseq_mask; |
1184 | 1196 | ||
1197 | /* Initialize DDB sites */ | ||
1198 | asd_seq_init_ddb_sites(asd_ha); | ||
1199 | |||
1185 | /* Initialize SCB sites. Done first to compute some values which | 1200 | /* Initialize SCB sites. Done first to compute some values which |
1186 | * the rest of the init code depends on. */ | 1201 | * the rest of the init code depends on. */ |
1187 | asd_init_scb_sites(asd_ha); | 1202 | asd_init_scb_sites(asd_ha); |
@@ -1232,6 +1247,13 @@ static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) | |||
1232 | return asd_seq_unpause_lseq(asd_ha, lseq); | 1247 | return asd_seq_unpause_lseq(asd_ha, lseq); |
1233 | } | 1248 | } |
1234 | 1249 | ||
1250 | int asd_release_firmware(void) | ||
1251 | { | ||
1252 | if (sequencer_fw) | ||
1253 | release_firmware(sequencer_fw); | ||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1235 | static int asd_request_firmware(struct asd_ha_struct *asd_ha) | 1257 | static int asd_request_firmware(struct asd_ha_struct *asd_ha) |
1236 | { | 1258 | { |
1237 | int err, i; | 1259 | int err, i; |
@@ -1375,7 +1397,9 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy) | |||
1375 | u8 phy_is_up; | 1397 | u8 phy_is_up; |
1376 | u8 mask; | 1398 | u8 mask; |
1377 | int i, err; | 1399 | int i, err; |
1400 | unsigned long flags; | ||
1378 | 1401 | ||
1402 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
1379 | for_each_phy(phy_mask, mask, i) | 1403 | for_each_phy(phy_mask, mask, i) |
1380 | asd_ddbsite_write_byte(asd_ha, 0, | 1404 | asd_ddbsite_write_byte(asd_ha, 0, |
1381 | offsetof(struct asd_ddb_seq_shared, | 1405 | offsetof(struct asd_ddb_seq_shared, |
@@ -1395,6 +1419,7 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy) | |||
1395 | break; | 1419 | break; |
1396 | } | 1420 | } |
1397 | } | 1421 | } |
1422 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
1398 | 1423 | ||
1399 | if (err) | 1424 | if (err) |
1400 | asd_printk("couldn't update DDB 0:error:%d\n", err); | 1425 | asd_printk("couldn't update DDB 0:error:%d\n", err); |
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index 9e715e5496af..9437ff0ae3a4 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h | |||
@@ -63,6 +63,7 @@ int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); | |||
63 | int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); | 63 | int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); |
64 | int asd_init_seqs(struct asd_ha_struct *asd_ha); | 64 | int asd_init_seqs(struct asd_ha_struct *asd_ha); |
65 | int asd_start_seqs(struct asd_ha_struct *asd_ha); | 65 | int asd_start_seqs(struct asd_ha_struct *asd_ha); |
66 | int asd_release_firmware(void); | ||
66 | 67 | ||
67 | void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy); | 68 | void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy); |
68 | #endif | 69 | #endif |
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index d202ed5a6709..e2ad5bed9403 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c | |||
@@ -349,6 +349,7 @@ Again: | |||
349 | 349 | ||
350 | spin_lock_irqsave(&task->task_state_lock, flags); | 350 | spin_lock_irqsave(&task->task_state_lock, flags); |
351 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; | 351 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; |
352 | task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; | ||
352 | task->task_state_flags |= SAS_TASK_STATE_DONE; | 353 | task->task_state_flags |= SAS_TASK_STATE_DONE; |
353 | if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { | 354 | if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { |
354 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 355 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
@@ -557,6 +558,7 @@ int asd_execute_task(struct sas_task *task, const int num, | |||
557 | struct sas_task *t = task; | 558 | struct sas_task *t = task; |
558 | struct asd_ascb *ascb = NULL, *a; | 559 | struct asd_ascb *ascb = NULL, *a; |
559 | struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; | 560 | struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; |
561 | unsigned long flags; | ||
560 | 562 | ||
561 | res = asd_can_queue(asd_ha, num); | 563 | res = asd_can_queue(asd_ha, num); |
562 | if (res) | 564 | if (res) |
@@ -599,6 +601,10 @@ int asd_execute_task(struct sas_task *task, const int num, | |||
599 | } | 601 | } |
600 | if (res) | 602 | if (res) |
601 | goto out_err_unmap; | 603 | goto out_err_unmap; |
604 | |||
605 | spin_lock_irqsave(&t->task_state_lock, flags); | ||
606 | t->task_state_flags |= SAS_TASK_AT_INITIATOR; | ||
607 | spin_unlock_irqrestore(&t->task_state_lock, flags); | ||
602 | } | 608 | } |
603 | list_del_init(&alist); | 609 | list_del_init(&alist); |
604 | 610 | ||
@@ -617,6 +623,9 @@ out_err_unmap: | |||
617 | if (a == b) | 623 | if (a == b) |
618 | break; | 624 | break; |
619 | t = a->uldd_task; | 625 | t = a->uldd_task; |
626 | spin_lock_irqsave(&t->task_state_lock, flags); | ||
627 | t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; | ||
628 | spin_unlock_irqrestore(&t->task_state_lock, flags); | ||
620 | switch (t->task_proto) { | 629 | switch (t->task_proto) { |
621 | case SATA_PROTO: | 630 | case SATA_PROTO: |
622 | case SAS_PROTO_STP: | 631 | case SAS_PROTO_STP: |
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 61234384503b..9a14a6d97275 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c | |||
@@ -566,9 +566,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, | |||
566 | res = TMF_RESP_FUNC_ESUPP; | 566 | res = TMF_RESP_FUNC_ESUPP; |
567 | break; | 567 | break; |
568 | default: | 568 | default: |
569 | ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n", | 569 | /* Allow TMF response codes to propagate upwards */ |
570 | __FUNCTION__, res); | ||
571 | res = TMF_RESP_FUNC_FAILED; | ||
572 | break; | 570 | break; |
573 | } | 571 | } |
574 | out_err: | 572 | out_err: |