diff options
| author | jack wang <jack_wang@usish.com> | 2009-12-07 04:22:42 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-10 11:00:12 -0500 |
| commit | 1cc943ae5003e4612a73119cb6fb637a45c2714d (patch) | |
| tree | 07d7c64475aaec5f05eeea86d13d81b27baee3e1 /drivers | |
| parent | 9e79e12554d651f586ff2364e69a8e9cd5e9dbcb (diff) | |
[SCSI] pm8001: enhance error handle for IO patch
Enhance error handle for IO patch, when the port is down, fast return phy
down for task.
Signed-off-by: Jack Wang <jack_wang@usish.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 29 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 49 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.h | 4 |
4 files changed, 84 insertions, 5 deletions
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 68695b72e1ef..3a121fbd4fc5 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c | |||
| @@ -2906,13 +2906,17 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
| 2906 | le32_to_cpu(pPayload->lr_evt_status_phyid_portid); | 2906 | le32_to_cpu(pPayload->lr_evt_status_phyid_portid); |
| 2907 | u8 link_rate = | 2907 | u8 link_rate = |
| 2908 | (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28); | 2908 | (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28); |
| 2909 | u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F); | ||
| 2909 | u8 phy_id = | 2910 | u8 phy_id = |
| 2910 | (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); | 2911 | (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); |
| 2912 | u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); | ||
| 2913 | u8 portstate = (u8)(npip_portstate & 0x0000000F); | ||
| 2914 | struct pm8001_port *port = &pm8001_ha->port[port_id]; | ||
| 2911 | struct sas_ha_struct *sas_ha = pm8001_ha->sas; | 2915 | struct sas_ha_struct *sas_ha = pm8001_ha->sas; |
| 2912 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; | 2916 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
| 2913 | unsigned long flags; | 2917 | unsigned long flags; |
| 2914 | u8 deviceType = pPayload->sas_identify.dev_type; | 2918 | u8 deviceType = pPayload->sas_identify.dev_type; |
| 2915 | 2919 | port->port_state = portstate; | |
| 2916 | PM8001_MSG_DBG(pm8001_ha, | 2920 | PM8001_MSG_DBG(pm8001_ha, |
| 2917 | pm8001_printk("HW_EVENT_SAS_PHY_UP \n")); | 2921 | pm8001_printk("HW_EVENT_SAS_PHY_UP \n")); |
| 2918 | 2922 | ||
| @@ -2925,16 +2929,19 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
| 2925 | PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); | 2929 | PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); |
| 2926 | pm8001_chip_phy_ctl_req(pm8001_ha, phy_id, | 2930 | pm8001_chip_phy_ctl_req(pm8001_ha, phy_id, |
| 2927 | PHY_NOTIFY_ENABLE_SPINUP); | 2931 | PHY_NOTIFY_ENABLE_SPINUP); |
| 2932 | port->port_attached = 1; | ||
| 2928 | get_lrate_mode(phy, link_rate); | 2933 | get_lrate_mode(phy, link_rate); |
| 2929 | break; | 2934 | break; |
| 2930 | case SAS_EDGE_EXPANDER_DEVICE: | 2935 | case SAS_EDGE_EXPANDER_DEVICE: |
| 2931 | PM8001_MSG_DBG(pm8001_ha, | 2936 | PM8001_MSG_DBG(pm8001_ha, |
| 2932 | pm8001_printk("expander device.\n")); | 2937 | pm8001_printk("expander device.\n")); |
| 2938 | port->port_attached = 1; | ||
| 2933 | get_lrate_mode(phy, link_rate); | 2939 | get_lrate_mode(phy, link_rate); |
| 2934 | break; | 2940 | break; |
| 2935 | case SAS_FANOUT_EXPANDER_DEVICE: | 2941 | case SAS_FANOUT_EXPANDER_DEVICE: |
| 2936 | PM8001_MSG_DBG(pm8001_ha, | 2942 | PM8001_MSG_DBG(pm8001_ha, |
| 2937 | pm8001_printk("fanout expander device.\n")); | 2943 | pm8001_printk("fanout expander device.\n")); |
| 2944 | port->port_attached = 1; | ||
| 2938 | get_lrate_mode(phy, link_rate); | 2945 | get_lrate_mode(phy, link_rate); |
| 2939 | break; | 2946 | break; |
| 2940 | default: | 2947 | default: |
| @@ -2976,11 +2983,17 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
| 2976 | le32_to_cpu(pPayload->lr_evt_status_phyid_portid); | 2983 | le32_to_cpu(pPayload->lr_evt_status_phyid_portid); |
| 2977 | u8 link_rate = | 2984 | u8 link_rate = |
| 2978 | (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28); | 2985 | (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28); |
| 2986 | u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F); | ||
| 2979 | u8 phy_id = | 2987 | u8 phy_id = |
| 2980 | (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); | 2988 | (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); |
| 2989 | u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); | ||
| 2990 | u8 portstate = (u8)(npip_portstate & 0x0000000F); | ||
| 2991 | struct pm8001_port *port = &pm8001_ha->port[port_id]; | ||
| 2981 | struct sas_ha_struct *sas_ha = pm8001_ha->sas; | 2992 | struct sas_ha_struct *sas_ha = pm8001_ha->sas; |
| 2982 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; | 2993 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
| 2983 | unsigned long flags; | 2994 | unsigned long flags; |
| 2995 | port->port_state = portstate; | ||
| 2996 | port->port_attached = 1; | ||
| 2984 | get_lrate_mode(phy, link_rate); | 2997 | get_lrate_mode(phy, link_rate); |
| 2985 | phy->phy_type |= PORT_TYPE_SATA; | 2998 | phy->phy_type |= PORT_TYPE_SATA; |
| 2986 | phy->phy_attached = 1; | 2999 | phy->phy_attached = 1; |
| @@ -3014,7 +3027,13 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
| 3014 | (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); | 3027 | (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); |
| 3015 | u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); | 3028 | u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); |
| 3016 | u8 portstate = (u8)(npip_portstate & 0x0000000F); | 3029 | u8 portstate = (u8)(npip_portstate & 0x0000000F); |
| 3017 | 3030 | struct pm8001_port *port = &pm8001_ha->port[port_id]; | |
| 3031 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; | ||
| 3032 | port->port_state = portstate; | ||
| 3033 | phy->phy_type = 0; | ||
| 3034 | phy->identify.device_type = 0; | ||
| 3035 | phy->phy_attached = 0; | ||
| 3036 | memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE); | ||
| 3018 | switch (portstate) { | 3037 | switch (portstate) { |
| 3019 | case PORT_VALID: | 3038 | case PORT_VALID: |
| 3020 | break; | 3039 | break; |
| @@ -3023,26 +3042,30 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
| 3023 | pm8001_printk(" PortInvalid portID %d \n", port_id)); | 3042 | pm8001_printk(" PortInvalid portID %d \n", port_id)); |
| 3024 | PM8001_MSG_DBG(pm8001_ha, | 3043 | PM8001_MSG_DBG(pm8001_ha, |
| 3025 | pm8001_printk(" Last phy Down and port invalid\n")); | 3044 | pm8001_printk(" Last phy Down and port invalid\n")); |
| 3045 | port->port_attached = 0; | ||
| 3026 | pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, | 3046 | pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, |
| 3027 | port_id, phy_id, 0, 0); | 3047 | port_id, phy_id, 0, 0); |
| 3028 | break; | 3048 | break; |
| 3029 | case PORT_IN_RESET: | 3049 | case PORT_IN_RESET: |
| 3030 | PM8001_MSG_DBG(pm8001_ha, | 3050 | PM8001_MSG_DBG(pm8001_ha, |
| 3031 | pm8001_printk(" PortInReset portID %d \n", port_id)); | 3051 | pm8001_printk(" Port In Reset portID %d \n", port_id)); |
| 3032 | break; | 3052 | break; |
| 3033 | case PORT_NOT_ESTABLISHED: | 3053 | case PORT_NOT_ESTABLISHED: |
| 3034 | PM8001_MSG_DBG(pm8001_ha, | 3054 | PM8001_MSG_DBG(pm8001_ha, |
| 3035 | pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n")); | 3055 | pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n")); |
| 3056 | port->port_attached = 0; | ||
| 3036 | break; | 3057 | break; |
| 3037 | case PORT_LOSTCOMM: | 3058 | case PORT_LOSTCOMM: |
| 3038 | PM8001_MSG_DBG(pm8001_ha, | 3059 | PM8001_MSG_DBG(pm8001_ha, |
| 3039 | pm8001_printk(" phy Down and PORT_LOSTCOMM\n")); | 3060 | pm8001_printk(" phy Down and PORT_LOSTCOMM\n")); |
| 3040 | PM8001_MSG_DBG(pm8001_ha, | 3061 | PM8001_MSG_DBG(pm8001_ha, |
| 3041 | pm8001_printk(" Last phy Down and port invalid\n")); | 3062 | pm8001_printk(" Last phy Down and port invalid\n")); |
| 3063 | port->port_attached = 0; | ||
| 3042 | pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, | 3064 | pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, |
| 3043 | port_id, phy_id, 0, 0); | 3065 | port_id, phy_id, 0, 0); |
| 3044 | break; | 3066 | break; |
| 3045 | default: | 3067 | default: |
| 3068 | port->port_attached = 0; | ||
| 3046 | PM8001_MSG_DBG(pm8001_ha, | 3069 | PM8001_MSG_DBG(pm8001_ha, |
| 3047 | pm8001_printk(" phy Down and(default) = %x\n", | 3070 | pm8001_printk(" phy Down and(default) = %x\n", |
| 3048 | portstate)); | 3071 | portstate)); |
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 42ebe725d5a5..fb6379a4bee4 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c | |||
| @@ -200,8 +200,13 @@ static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha) | |||
| 200 | { | 200 | { |
| 201 | int i; | 201 | int i; |
| 202 | spin_lock_init(&pm8001_ha->lock); | 202 | spin_lock_init(&pm8001_ha->lock); |
| 203 | for (i = 0; i < pm8001_ha->chip->n_phy; i++) | 203 | for (i = 0; i < pm8001_ha->chip->n_phy; i++) { |
| 204 | pm8001_phy_init(pm8001_ha, i); | 204 | pm8001_phy_init(pm8001_ha, i); |
| 205 | pm8001_ha->port[i].wide_port_phymap = 0; | ||
| 206 | pm8001_ha->port[i].port_attached = 0; | ||
| 207 | pm8001_ha->port[i].port_state = 0; | ||
| 208 | INIT_LIST_HEAD(&pm8001_ha->port[i].list); | ||
| 209 | } | ||
| 205 | 210 | ||
| 206 | pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL); | 211 | pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL); |
| 207 | if (!pm8001_ha->tags) | 212 | if (!pm8001_ha->tags) |
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 1f767a0e727a..49721c886c26 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c | |||
| @@ -329,6 +329,23 @@ int pm8001_slave_configure(struct scsi_device *sdev) | |||
| 329 | } | 329 | } |
| 330 | return 0; | 330 | return 0; |
| 331 | } | 331 | } |
| 332 | /* Find the local port id that's attached to this device */ | ||
| 333 | static int sas_find_local_port_id(struct domain_device *dev) | ||
| 334 | { | ||
| 335 | struct domain_device *pdev = dev->parent; | ||
| 336 | |||
| 337 | /* Directly attached device */ | ||
| 338 | if (!pdev) | ||
| 339 | return dev->port->id; | ||
| 340 | while (pdev) { | ||
| 341 | struct domain_device *pdev_p = pdev->parent; | ||
| 342 | if (!pdev_p) | ||
| 343 | return pdev->port->id; | ||
| 344 | pdev = pdev->parent; | ||
| 345 | } | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 332 | /** | 349 | /** |
| 333 | * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware. | 350 | * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware. |
| 334 | * @task: the task to be execute. | 351 | * @task: the task to be execute. |
| @@ -346,11 +363,12 @@ static int pm8001_task_exec(struct sas_task *task, const int num, | |||
| 346 | struct domain_device *dev = task->dev; | 363 | struct domain_device *dev = task->dev; |
| 347 | struct pm8001_hba_info *pm8001_ha; | 364 | struct pm8001_hba_info *pm8001_ha; |
| 348 | struct pm8001_device *pm8001_dev; | 365 | struct pm8001_device *pm8001_dev; |
| 366 | struct pm8001_port *port = NULL; | ||
| 349 | struct sas_task *t = task; | 367 | struct sas_task *t = task; |
| 350 | struct pm8001_ccb_info *ccb; | 368 | struct pm8001_ccb_info *ccb; |
| 351 | u32 tag = 0xdeadbeef, rc, n_elem = 0; | 369 | u32 tag = 0xdeadbeef, rc, n_elem = 0; |
| 352 | u32 n = num; | 370 | u32 n = num; |
| 353 | unsigned long flags = 0; | 371 | unsigned long flags = 0, flags_libsas = 0; |
| 354 | 372 | ||
| 355 | if (!dev->port) { | 373 | if (!dev->port) { |
| 356 | struct task_status_struct *tsm = &t->task_status; | 374 | struct task_status_struct *tsm = &t->task_status; |
| @@ -379,6 +397,35 @@ static int pm8001_task_exec(struct sas_task *task, const int num, | |||
| 379 | rc = SAS_PHY_DOWN; | 397 | rc = SAS_PHY_DOWN; |
| 380 | goto out_done; | 398 | goto out_done; |
| 381 | } | 399 | } |
| 400 | port = &pm8001_ha->port[sas_find_local_port_id(dev)]; | ||
| 401 | if (!port->port_attached) { | ||
| 402 | if (sas_protocol_ata(t->task_proto)) { | ||
| 403 | struct task_status_struct *ts = &t->task_status; | ||
| 404 | ts->resp = SAS_TASK_UNDELIVERED; | ||
| 405 | ts->stat = SAS_PHY_DOWN; | ||
| 406 | |||
| 407 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); | ||
| 408 | spin_unlock_irqrestore(dev->sata_dev.ap->lock, | ||
| 409 | flags_libsas); | ||
| 410 | t->task_done(t); | ||
| 411 | spin_lock_irqsave(dev->sata_dev.ap->lock, | ||
| 412 | flags_libsas); | ||
| 413 | spin_lock_irqsave(&pm8001_ha->lock, flags); | ||
| 414 | if (n > 1) | ||
| 415 | t = list_entry(t->list.next, | ||
| 416 | struct sas_task, list); | ||
| 417 | continue; | ||
| 418 | } else { | ||
| 419 | struct task_status_struct *ts = &t->task_status; | ||
| 420 | ts->resp = SAS_TASK_UNDELIVERED; | ||
| 421 | ts->stat = SAS_PHY_DOWN; | ||
| 422 | t->task_done(t); | ||
| 423 | if (n > 1) | ||
| 424 | t = list_entry(t->list.next, | ||
| 425 | struct sas_task, list); | ||
| 426 | continue; | ||
| 427 | } | ||
| 428 | } | ||
| 382 | rc = pm8001_tag_alloc(pm8001_ha, &tag); | 429 | rc = pm8001_tag_alloc(pm8001_ha, &tag); |
| 383 | if (rc) | 430 | if (rc) |
| 384 | goto err_out; | 431 | goto err_out; |
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 30f2ede55a75..c44a1150d70d 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h | |||
| @@ -164,6 +164,10 @@ struct pm8001_chip_info { | |||
| 164 | 164 | ||
| 165 | struct pm8001_port { | 165 | struct pm8001_port { |
| 166 | struct asd_sas_port sas_port; | 166 | struct asd_sas_port sas_port; |
| 167 | u8 port_attached; | ||
| 168 | u8 wide_port_phymap; | ||
| 169 | u8 port_state; | ||
| 170 | struct list_head list; | ||
| 167 | }; | 171 | }; |
| 168 | 172 | ||
| 169 | struct pm8001_phy { | 173 | struct pm8001_phy { |
