diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_sas.c')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 119 |
1 files changed, 104 insertions, 15 deletions
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index b961112395d5..a85d73de7c80 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver | 2 | * PMC-Sierra PM8001/8081/8088/8089 SAS/SATA based host adapters driver |
3 | * | 3 | * |
4 | * Copyright (c) 2008-2009 USI Co., Ltd. | 4 | * Copyright (c) 2008-2009 USI Co., Ltd. |
5 | * All rights reserved. | 5 | * All rights reserved. |
@@ -68,7 +68,7 @@ static void pm8001_tag_clear(struct pm8001_hba_info *pm8001_ha, u32 tag) | |||
68 | clear_bit(tag, bitmap); | 68 | clear_bit(tag, bitmap); |
69 | } | 69 | } |
70 | 70 | ||
71 | static void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag) | 71 | void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag) |
72 | { | 72 | { |
73 | pm8001_tag_clear(pm8001_ha, tag); | 73 | pm8001_tag_clear(pm8001_ha, tag); |
74 | } | 74 | } |
@@ -212,10 +212,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, | |||
212 | break; | 212 | break; |
213 | case PHY_FUNC_GET_EVENTS: | 213 | case PHY_FUNC_GET_EVENTS: |
214 | spin_lock_irqsave(&pm8001_ha->lock, flags); | 214 | spin_lock_irqsave(&pm8001_ha->lock, flags); |
215 | if (-1 == pm8001_bar4_shift(pm8001_ha, | 215 | if (pm8001_ha->chip_id == chip_8001) { |
216 | if (-1 == pm8001_bar4_shift(pm8001_ha, | ||
216 | (phy_id < 4) ? 0x30000 : 0x40000)) { | 217 | (phy_id < 4) ? 0x30000 : 0x40000)) { |
217 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); | 218 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); |
218 | return -EINVAL; | 219 | return -EINVAL; |
220 | } | ||
219 | } | 221 | } |
220 | { | 222 | { |
221 | struct sas_phy *phy = sas_phy->phy; | 223 | struct sas_phy *phy = sas_phy->phy; |
@@ -228,7 +230,8 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, | |||
228 | phy->loss_of_dword_sync_count = qp[3]; | 230 | phy->loss_of_dword_sync_count = qp[3]; |
229 | phy->phy_reset_problem_count = qp[4]; | 231 | phy->phy_reset_problem_count = qp[4]; |
230 | } | 232 | } |
231 | pm8001_bar4_shift(pm8001_ha, 0); | 233 | if (pm8001_ha->chip_id == chip_8001) |
234 | pm8001_bar4_shift(pm8001_ha, 0); | ||
232 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); | 235 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); |
233 | return 0; | 236 | return 0; |
234 | default: | 237 | default: |
@@ -249,7 +252,9 @@ void pm8001_scan_start(struct Scsi_Host *shost) | |||
249 | struct pm8001_hba_info *pm8001_ha; | 252 | struct pm8001_hba_info *pm8001_ha; |
250 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); | 253 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
251 | pm8001_ha = sha->lldd_ha; | 254 | pm8001_ha = sha->lldd_ha; |
252 | PM8001_CHIP_DISP->sas_re_init_req(pm8001_ha); | 255 | /* SAS_RE_INITIALIZATION not available in SPCv/ve */ |
256 | if (pm8001_ha->chip_id == chip_8001) | ||
257 | PM8001_CHIP_DISP->sas_re_init_req(pm8001_ha); | ||
253 | for (i = 0; i < pm8001_ha->chip->n_phy; ++i) | 258 | for (i = 0; i < pm8001_ha->chip->n_phy; ++i) |
254 | PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i); | 259 | PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i); |
255 | } | 260 | } |
@@ -352,7 +357,7 @@ static int sas_find_local_port_id(struct domain_device *dev) | |||
352 | * @tmf: the task management IU | 357 | * @tmf: the task management IU |
353 | */ | 358 | */ |
354 | #define DEV_IS_GONE(pm8001_dev) \ | 359 | #define DEV_IS_GONE(pm8001_dev) \ |
355 | ((!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE))) | 360 | ((!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED))) |
356 | static int pm8001_task_exec(struct sas_task *task, const int num, | 361 | static int pm8001_task_exec(struct sas_task *task, const int num, |
357 | gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf) | 362 | gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf) |
358 | { | 363 | { |
@@ -370,7 +375,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num, | |||
370 | struct task_status_struct *tsm = &t->task_status; | 375 | struct task_status_struct *tsm = &t->task_status; |
371 | tsm->resp = SAS_TASK_UNDELIVERED; | 376 | tsm->resp = SAS_TASK_UNDELIVERED; |
372 | tsm->stat = SAS_PHY_DOWN; | 377 | tsm->stat = SAS_PHY_DOWN; |
373 | if (dev->dev_type != SATA_DEV) | 378 | if (dev->dev_type != SAS_SATA_DEV) |
374 | t->task_done(t); | 379 | t->task_done(t); |
375 | return 0; | 380 | return 0; |
376 | } | 381 | } |
@@ -548,7 +553,7 @@ struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha) | |||
548 | { | 553 | { |
549 | u32 dev; | 554 | u32 dev; |
550 | for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) { | 555 | for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) { |
551 | if (pm8001_ha->devices[dev].dev_type == NO_DEVICE) { | 556 | if (pm8001_ha->devices[dev].dev_type == SAS_PHY_UNUSED) { |
552 | pm8001_ha->devices[dev].id = dev; | 557 | pm8001_ha->devices[dev].id = dev; |
553 | return &pm8001_ha->devices[dev]; | 558 | return &pm8001_ha->devices[dev]; |
554 | } | 559 | } |
@@ -560,13 +565,31 @@ struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha) | |||
560 | } | 565 | } |
561 | return NULL; | 566 | return NULL; |
562 | } | 567 | } |
568 | /** | ||
569 | * pm8001_find_dev - find a matching pm8001_device | ||
570 | * @pm8001_ha: our hba card information | ||
571 | */ | ||
572 | struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha, | ||
573 | u32 device_id) | ||
574 | { | ||
575 | u32 dev; | ||
576 | for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) { | ||
577 | if (pm8001_ha->devices[dev].device_id == device_id) | ||
578 | return &pm8001_ha->devices[dev]; | ||
579 | } | ||
580 | if (dev == PM8001_MAX_DEVICES) { | ||
581 | PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("NO MATCHING " | ||
582 | "DEVICE FOUND !!!\n")); | ||
583 | } | ||
584 | return NULL; | ||
585 | } | ||
563 | 586 | ||
564 | static void pm8001_free_dev(struct pm8001_device *pm8001_dev) | 587 | static void pm8001_free_dev(struct pm8001_device *pm8001_dev) |
565 | { | 588 | { |
566 | u32 id = pm8001_dev->id; | 589 | u32 id = pm8001_dev->id; |
567 | memset(pm8001_dev, 0, sizeof(*pm8001_dev)); | 590 | memset(pm8001_dev, 0, sizeof(*pm8001_dev)); |
568 | pm8001_dev->id = id; | 591 | pm8001_dev->id = id; |
569 | pm8001_dev->dev_type = NO_DEVICE; | 592 | pm8001_dev->dev_type = SAS_PHY_UNUSED; |
570 | pm8001_dev->device_id = PM8001_MAX_DEVICES; | 593 | pm8001_dev->device_id = PM8001_MAX_DEVICES; |
571 | pm8001_dev->sas_device = NULL; | 594 | pm8001_dev->sas_device = NULL; |
572 | } | 595 | } |
@@ -624,7 +647,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) | |||
624 | res = -1; | 647 | res = -1; |
625 | } | 648 | } |
626 | } else { | 649 | } else { |
627 | if (dev->dev_type == SATA_DEV) { | 650 | if (dev->dev_type == SAS_SATA_DEV) { |
628 | pm8001_device->attached_phy = | 651 | pm8001_device->attached_phy = |
629 | dev->rphy->identify.phy_identifier; | 652 | dev->rphy->identify.phy_identifier; |
630 | flag = 1; /* directly sata*/ | 653 | flag = 1; /* directly sata*/ |
@@ -634,7 +657,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) | |||
634 | PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag); | 657 | PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag); |
635 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); | 658 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); |
636 | wait_for_completion(&completion); | 659 | wait_for_completion(&completion); |
637 | if (dev->dev_type == SAS_END_DEV) | 660 | if (dev->dev_type == SAS_END_DEVICE) |
638 | msleep(50); | 661 | msleep(50); |
639 | pm8001_ha->flags = PM8001F_RUN_TIME; | 662 | pm8001_ha->flags = PM8001F_RUN_TIME; |
640 | return 0; | 663 | return 0; |
@@ -648,7 +671,7 @@ int pm8001_dev_found(struct domain_device *dev) | |||
648 | return pm8001_dev_found_notify(dev); | 671 | return pm8001_dev_found_notify(dev); |
649 | } | 672 | } |
650 | 673 | ||
651 | static void pm8001_task_done(struct sas_task *task) | 674 | void pm8001_task_done(struct sas_task *task) |
652 | { | 675 | { |
653 | if (!del_timer(&task->slow_task->timer)) | 676 | if (!del_timer(&task->slow_task->timer)) |
654 | return; | 677 | return; |
@@ -904,7 +927,7 @@ void pm8001_open_reject_retry( | |||
904 | struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i]; | 927 | struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i]; |
905 | 928 | ||
906 | pm8001_dev = ccb->device; | 929 | pm8001_dev = ccb->device; |
907 | if (!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE)) | 930 | if (!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED)) |
908 | continue; | 931 | continue; |
909 | if (!device_to_close) { | 932 | if (!device_to_close) { |
910 | uintptr_t d = (uintptr_t)pm8001_dev | 933 | uintptr_t d = (uintptr_t)pm8001_dev |
@@ -995,6 +1018,72 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) | |||
995 | return rc; | 1018 | return rc; |
996 | } | 1019 | } |
997 | 1020 | ||
1021 | /* | ||
1022 | * This function handle the IT_NEXUS_XXX event or completion | ||
1023 | * status code for SSP/SATA/SMP I/O request. | ||
1024 | */ | ||
1025 | int pm8001_I_T_nexus_event_handler(struct domain_device *dev) | ||
1026 | { | ||
1027 | int rc = TMF_RESP_FUNC_FAILED; | ||
1028 | struct pm8001_device *pm8001_dev; | ||
1029 | struct pm8001_hba_info *pm8001_ha; | ||
1030 | struct sas_phy *phy; | ||
1031 | u32 device_id = 0; | ||
1032 | |||
1033 | if (!dev || !dev->lldd_dev) | ||
1034 | return -1; | ||
1035 | |||
1036 | pm8001_dev = dev->lldd_dev; | ||
1037 | device_id = pm8001_dev->device_id; | ||
1038 | pm8001_ha = pm8001_find_ha_by_dev(dev); | ||
1039 | |||
1040 | PM8001_EH_DBG(pm8001_ha, | ||
1041 | pm8001_printk("I_T_Nexus handler invoked !!")); | ||
1042 | |||
1043 | phy = sas_get_local_phy(dev); | ||
1044 | |||
1045 | if (dev_is_sata(dev)) { | ||
1046 | DECLARE_COMPLETION_ONSTACK(completion_setstate); | ||
1047 | if (scsi_is_sas_phy_local(phy)) { | ||
1048 | rc = 0; | ||
1049 | goto out; | ||
1050 | } | ||
1051 | /* send internal ssp/sata/smp abort command to FW */ | ||
1052 | rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , | ||
1053 | dev, 1, 0); | ||
1054 | msleep(100); | ||
1055 | |||
1056 | /* deregister the target device */ | ||
1057 | pm8001_dev_gone_notify(dev); | ||
1058 | msleep(200); | ||
1059 | |||
1060 | /*send phy reset to hard reset target */ | ||
1061 | rc = sas_phy_reset(phy, 1); | ||
1062 | msleep(2000); | ||
1063 | pm8001_dev->setds_completion = &completion_setstate; | ||
1064 | |||
1065 | wait_for_completion(&completion_setstate); | ||
1066 | } else { | ||
1067 | /* send internal ssp/sata/smp abort command to FW */ | ||
1068 | rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , | ||
1069 | dev, 1, 0); | ||
1070 | msleep(100); | ||
1071 | |||
1072 | /* deregister the target device */ | ||
1073 | pm8001_dev_gone_notify(dev); | ||
1074 | msleep(200); | ||
1075 | |||
1076 | /*send phy reset to hard reset target */ | ||
1077 | rc = sas_phy_reset(phy, 1); | ||
1078 | msleep(2000); | ||
1079 | } | ||
1080 | PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n", | ||
1081 | pm8001_dev->device_id, rc)); | ||
1082 | out: | ||
1083 | sas_put_local_phy(phy); | ||
1084 | |||
1085 | return rc; | ||
1086 | } | ||
998 | /* mandatory SAM-3, the task reset the specified LUN*/ | 1087 | /* mandatory SAM-3, the task reset the specified LUN*/ |
999 | int pm8001_lu_reset(struct domain_device *dev, u8 *lun) | 1088 | int pm8001_lu_reset(struct domain_device *dev, u8 *lun) |
1000 | { | 1089 | { |