[SCSI] pm8001: enhance error handle for IO patch
authorjack wang <jack_wang@usish.com>
Mon, 7 Dec 2009 09:22:42 +0000 (17:22 +0800)
committerJames Bottomley <James.Bottomley@suse.de>
Thu, 10 Dec 2009 16:00:12 +0000 (10:00 -0600)
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>
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm8001_sas.h

index 68695b72e1eff6efff380feedf2b29eb6d3f8a5f..3a121fbd4fc5c20f97185482edfcfff25ada909e 100644 (file)
@@ -2906,13 +2906,17 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
                le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
        u8 link_rate =
                (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
+       u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
        u8 phy_id =
                (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+       u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
+       u8 portstate = (u8)(npip_portstate & 0x0000000F);
+       struct pm8001_port *port = &pm8001_ha->port[port_id];
        struct sas_ha_struct *sas_ha = pm8001_ha->sas;
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        unsigned long flags;
        u8 deviceType = pPayload->sas_identify.dev_type;
-
+       port->port_state =  portstate;
        PM8001_MSG_DBG(pm8001_ha,
                pm8001_printk("HW_EVENT_SAS_PHY_UP \n"));
 
@@ -2925,16 +2929,19 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
                PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n"));
                pm8001_chip_phy_ctl_req(pm8001_ha, phy_id,
                        PHY_NOTIFY_ENABLE_SPINUP);
+               port->port_attached = 1;
                get_lrate_mode(phy, link_rate);
                break;
        case SAS_EDGE_EXPANDER_DEVICE:
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk("expander device.\n"));
+               port->port_attached = 1;
                get_lrate_mode(phy, link_rate);
                break;
        case SAS_FANOUT_EXPANDER_DEVICE:
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk("fanout expander device.\n"));
+               port->port_attached = 1;
                get_lrate_mode(phy, link_rate);
                break;
        default:
@@ -2976,11 +2983,17 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
                le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
        u8 link_rate =
                (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
+       u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
        u8 phy_id =
                (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
+       u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
+       u8 portstate = (u8)(npip_portstate & 0x0000000F);
+       struct pm8001_port *port = &pm8001_ha->port[port_id];
        struct sas_ha_struct *sas_ha = pm8001_ha->sas;
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        unsigned long flags;
+       port->port_state =  portstate;
+       port->port_attached = 1;
        get_lrate_mode(phy, link_rate);
        phy->phy_type |= PORT_TYPE_SATA;
        phy->phy_attached = 1;
@@ -3014,7 +3027,13 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
                (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
        u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
        u8 portstate = (u8)(npip_portstate & 0x0000000F);
-
+       struct pm8001_port *port = &pm8001_ha->port[port_id];
+       struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
+       port->port_state =  portstate;
+       phy->phy_type = 0;
+       phy->identify.device_type = 0;
+       phy->phy_attached = 0;
+       memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE);
        switch (portstate) {
        case PORT_VALID:
                break;
@@ -3023,26 +3042,30 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        pm8001_printk(" PortInvalid portID %d \n", port_id));
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk(" Last phy Down and port invalid\n"));
+               port->port_attached = 0;
                pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
                        port_id, phy_id, 0, 0);
                break;
        case PORT_IN_RESET:
                PM8001_MSG_DBG(pm8001_ha,
-                       pm8001_printk(" PortInReset portID %d \n", port_id));
+                       pm8001_printk(" Port In Reset portID %d \n", port_id));
                break;
        case PORT_NOT_ESTABLISHED:
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n"));
+               port->port_attached = 0;
                break;
        case PORT_LOSTCOMM:
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk(" phy Down and PORT_LOSTCOMM\n"));
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk(" Last phy Down and port invalid\n"));
+               port->port_attached = 0;
                pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
                        port_id, phy_id, 0, 0);
                break;
        default:
+               port->port_attached = 0;
                PM8001_MSG_DBG(pm8001_ha,
                        pm8001_printk(" phy Down and(default) = %x\n",
                        portstate));
index 42ebe725d5a509ea911118d217d61a5430599637..fb6379a4bee46a04cafd9ff38fcb7f997f8c1b64 100644 (file)
@@ -200,8 +200,13 @@ static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
 {
        int i;
        spin_lock_init(&pm8001_ha->lock);
-       for (i = 0; i < pm8001_ha->chip->n_phy; i++)
+       for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
                pm8001_phy_init(pm8001_ha, i);
+               pm8001_ha->port[i].wide_port_phymap = 0;
+               pm8001_ha->port[i].port_attached = 0;
+               pm8001_ha->port[i].port_state = 0;
+               INIT_LIST_HEAD(&pm8001_ha->port[i].list);
+       }
 
        pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL);
        if (!pm8001_ha->tags)
index 1f767a0e727a9b46d5fc4e073576c1422e3b9eea..49721c886c26fb93a7fe41509d8d797252985fd2 100644 (file)
@@ -329,6 +329,23 @@ int pm8001_slave_configure(struct scsi_device *sdev)
        }
        return 0;
 }
+ /* Find the local port id that's attached to this device */
+static int sas_find_local_port_id(struct domain_device *dev)
+{
+       struct domain_device *pdev = dev->parent;
+
+       /* Directly attached device */
+       if (!pdev)
+               return dev->port->id;
+       while (pdev) {
+               struct domain_device *pdev_p = pdev->parent;
+               if (!pdev_p)
+                       return pdev->port->id;
+               pdev = pdev->parent;
+       }
+       return 0;
+}
+
 /**
   * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware.
   * @task: the task to be execute.
@@ -346,11 +363,12 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
        struct domain_device *dev = task->dev;
        struct pm8001_hba_info *pm8001_ha;
        struct pm8001_device *pm8001_dev;
+       struct pm8001_port *port = NULL;
        struct sas_task *t = task;
        struct pm8001_ccb_info *ccb;
        u32 tag = 0xdeadbeef, rc, n_elem = 0;
        u32 n = num;
-       unsigned long flags = 0;
+       unsigned long flags = 0, flags_libsas = 0;
 
        if (!dev->port) {
                struct task_status_struct *tsm = &t->task_status;
@@ -379,6 +397,35 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
                        rc = SAS_PHY_DOWN;
                        goto out_done;
                }
+               port = &pm8001_ha->port[sas_find_local_port_id(dev)];
+               if (!port->port_attached) {
+                       if (sas_protocol_ata(t->task_proto)) {
+                               struct task_status_struct *ts = &t->task_status;
+                               ts->resp = SAS_TASK_UNDELIVERED;
+                               ts->stat = SAS_PHY_DOWN;
+
+                               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                               spin_unlock_irqrestore(dev->sata_dev.ap->lock,
+                                               flags_libsas);
+                               t->task_done(t);
+                               spin_lock_irqsave(dev->sata_dev.ap->lock,
+                                       flags_libsas);
+                               spin_lock_irqsave(&pm8001_ha->lock, flags);
+                               if (n > 1)
+                                       t = list_entry(t->list.next,
+                                                       struct sas_task, list);
+                               continue;
+                       } else {
+                               struct task_status_struct *ts = &t->task_status;
+                               ts->resp = SAS_TASK_UNDELIVERED;
+                               ts->stat = SAS_PHY_DOWN;
+                               t->task_done(t);
+                               if (n > 1)
+                                       t = list_entry(t->list.next,
+                                                       struct sas_task, list);
+                               continue;
+                       }
+               }
                rc = pm8001_tag_alloc(pm8001_ha, &tag);
                if (rc)
                        goto err_out;
index 30f2ede55a756c8cf36f264e0467334d6ea7df49..c44a1150d70d8b92da6356dc17715d16897a9ea1 100644 (file)
@@ -164,6 +164,10 @@ struct pm8001_chip_info {
 
 struct pm8001_port {
        struct asd_sas_port     sas_port;
+       u8                      port_attached;
+       u8                      wide_port_phymap;
+       u8                      port_state;
+       struct list_head        list;
 };
 
 struct pm8001_phy {