mv643xx_eth: fix unicast address filter corruption on mtu change
[safe/jmp/linux-2.6] / drivers / scsi / aic94xx / aic94xx_scb.c
index 14d5d8c..ca55013 100644 (file)
@@ -24,7 +24,6 @@
  *
  */
 
-#include <linux/pci.h>
 #include <scsi/scsi_host.h>
 
 #include "aic94xx.h"
@@ -51,7 +50,7 @@
                           | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
                           | CURRENT_OOB_ERROR)
 
-static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
+static void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
 {
        struct sas_phy *sas_phy = phy->sas_phy.phy;
 
@@ -82,7 +81,7 @@ static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
                phy->sas_phy.oob_mode = SATA_OOB_MODE;
 }
 
-static inline void asd_phy_event_tasklet(struct asd_ascb *ascb,
+static void asd_phy_event_tasklet(struct asd_ascb *ascb,
                                         struct done_list_struct *dl)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
@@ -126,8 +125,7 @@ static inline void asd_phy_event_tasklet(struct asd_ascb *ascb,
 }
 
 /* If phys are enabled sparsely, this will do the right thing. */
-static inline unsigned ord_phy(struct asd_ha_struct *asd_ha,
-                              struct asd_phy *phy)
+static unsigned ord_phy(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
 {
        u8 enabled_mask = asd_ha->hw_prof.enabled_phys;
        int i, k = 0;
@@ -152,7 +150,7 @@ static inline unsigned ord_phy(struct asd_ha_struct *asd_ha,
  * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
  * buffer.
  */
-static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
+static void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
 {
        if (phy->sas_phy.frame_rcvd[0] == 0x34
            && phy->sas_phy.oob_mode == SATA_OOB_MODE) {
@@ -213,7 +211,7 @@ static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
                phy->asd_port = port;
        }
        ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
-                   __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
+                   __func__, phy->asd_port->phy_mask, sas_phy->id);
        asd_update_port_links(asd_ha, phy);
        spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 }
@@ -233,9 +231,9 @@ static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
        spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 }
 
-static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
-                                          struct done_list_struct *dl,
-                                          int edb_id, int phy_id)
+static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
+                                   struct done_list_struct *dl,
+                                   int edb_id, int phy_id)
 {
        unsigned long flags;
        int edb_el = edb_id + ascb->edb_index;
@@ -256,9 +254,9 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
        sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
 }
 
-static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
-                                             struct done_list_struct *dl,
-                                             int phy_id)
+static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
+                                      struct done_list_struct *dl,
+                                      int phy_id)
 {
        struct asd_ha_struct *asd_ha = ascb->ha;
        struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
@@ -296,7 +294,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
                struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
                                                          GFP_ATOMIC);
                if (!cp) {
-                       asd_printk("%s: out of memory\n", __FUNCTION__);
+                       asd_printk("%s: out of memory\n", __func__);
                        goto out;
                }
                ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
@@ -309,9 +307,9 @@ out:
        ;
 }
 
-static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
-                                             struct done_list_struct *dl,
-                                             int phy_id)
+static void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
+                                      struct done_list_struct *dl,
+                                      int phy_id)
 {
        unsigned long flags;
        struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
@@ -413,39 +411,6 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
        }
 }
 
-/* hard reset a phy later */
-static void do_phy_reset_later(void *data)
-{
-       struct sas_phy *sas_phy = data;
-       int error;
-
-       ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
-                   sas_phy->identify.phy_identifier);
-       /* Reset device port */
-       error = sas_phy_reset(sas_phy, 1);
-       if (error)
-               ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
-                           __FUNCTION__, sas_phy->identify.phy_identifier, error);
-}
-
-static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
-{
-       INIT_WORK(&sas_phy->reset_work, do_phy_reset_later, sas_phy);
-       queue_work(shost->work_q, &sas_phy->reset_work);
-}
-
-/* start up the ABORT TASK tmf... */
-static void task_kill_later(struct asd_ascb *ascb)
-{
-       struct asd_ha_struct *asd_ha = ascb->ha;
-       struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
-       struct Scsi_Host *shost = sas_ha->core.shost;
-       struct sas_task *task = ascb->uldd_task;
-
-       INIT_WORK(&task->abort_work, (void (*)(void *))sas_task_abort, task);
-       queue_work(shost->work_q, &task->abort_work);
-}
-
 static void escb_tasklet_complete(struct asd_ascb *ascb,
                                  struct done_list_struct *dl)
 {
@@ -478,66 +443,116 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
        case REQ_TASK_ABORT: {
                struct asd_ascb *a, *b;
                u16 tc_abort;
+               struct domain_device *failed_dev = NULL;
+
+               ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
+                           __func__, dl->status_block[3]);
 
+               /*
+                * Find the task that caused the abort and abort it first.
+                * The sequencer won't put anything on the done list until
+                * that happens.
+                */
                tc_abort = *((u16*)(&dl->status_block[1]));
                tc_abort = le16_to_cpu(tc_abort);
 
-               ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
-                           __FUNCTION__, dl->status_block[3]);
+               list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
+                       struct sas_task *task = a->uldd_task;
 
-               /* Find the pending task and abort it. */
-               list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list)
-                       if (a->tc_index == tc_abort) {
-                               task_kill_later(a);
-                               break;
+                       if (a->tc_index != tc_abort)
+                               continue;
+
+                       if (task) {
+                               failed_dev = task->dev;
+                               sas_task_abort(task);
+                       } else {
+                               ASD_DPRINTK("R_T_A for non TASK scb 0x%x\n",
+                                           a->scb->header.opcode);
                        }
+                       break;
+               }
+
+               if (!failed_dev) {
+                       ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
+                                   __func__, tc_abort);
+                       goto out;
+               }
+
+               /*
+                * Now abort everything else for that device (hba?) so
+                * that the EH will wake up and do something.
+                */
+               list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
+                       struct sas_task *task = a->uldd_task;
+
+                       if (task &&
+                           task->dev == failed_dev &&
+                           a->tc_index != tc_abort)
+                               sas_task_abort(task);
+               }
+
                goto out;
        }
        case REQ_DEVICE_RESET: {
-               struct Scsi_Host *shost = sas_ha->core.shost;
-               struct sas_phy *dev_phy;
                struct asd_ascb *a;
                u16 conn_handle;
+               unsigned long flags;
+               struct sas_task *last_dev_task = NULL;
 
                conn_handle = *((u16*)(&dl->status_block[1]));
                conn_handle = le16_to_cpu(conn_handle);
 
-               ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
+               ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __func__,
                            dl->status_block[3]);
 
-               /* Kill all pending tasks and reset the device */
-               dev_phy = NULL;
+               /* Find the last pending task for the device... */
                list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
-                       struct sas_task *task;
-                       struct domain_device *dev;
                        u16 x;
+                       struct domain_device *dev;
+                       struct sas_task *task = a->uldd_task;
 
-                       task = a->uldd_task;
                        if (!task)
                                continue;
                        dev = task->dev;
 
                        x = (unsigned long)dev->lldd_dev;
-                       if (x == conn_handle) {
-                               dev_phy = dev->port->phy;
-                               task_kill_later(a);
-                       }
+                       if (x == conn_handle)
+                               last_dev_task = task;
                }
 
-               /* Reset device port */
-               if (!dev_phy) {
-                       ASD_DPRINTK("%s: No pending commands; can't reset.\n",
-                                   __FUNCTION__);
+               if (!last_dev_task) {
+                       ASD_DPRINTK("%s: Device reset for idle device %d?\n",
+                                   __func__, conn_handle);
                        goto out;
                }
-               phy_reset_later(dev_phy, shost);
+
+               /* ...and set the reset flag */
+               spin_lock_irqsave(&last_dev_task->task_state_lock, flags);
+               last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+               spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags);
+
+               /* Kill all pending tasks for the device */
+               list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
+                       u16 x;
+                       struct domain_device *dev;
+                       struct sas_task *task = a->uldd_task;
+
+                       if (!task)
+                               continue;
+                       dev = task->dev;
+
+                       x = (unsigned long)dev->lldd_dev;
+                       if (x == conn_handle)
+                               sas_task_abort(task);
+               }
+
                goto out;
        }
        case SIGNAL_NCQ_ERROR:
-               ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
+               ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __func__);
                goto out;
        case CLEAR_NCQ_ERROR:
-               ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
+               ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __func__);
                goto out;
        }
 
@@ -545,26 +560,26 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
        switch (sb_opcode) {
        case BYTES_DMAED:
-               ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
+               ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id);
                asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
                break;
        case PRIMITIVE_RECVD:
-               ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
+               ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__,
                            phy_id);
                asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
                break;
        case PHY_EVENT:
-               ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
+               ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id);
                asd_phy_event_tasklet(ascb, dl);
                break;
        case LINK_RESET_ERROR:
-               ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
+               ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__,
                            phy_id);
                asd_link_reset_err_tasklet(ascb, dl, phy_id);
                break;
        case TIMER_EVENT:
                ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
-                           __FUNCTION__, phy_id);
+                           __func__, phy_id);
                asd_turn_led(asd_ha, phy_id, 0);
                /* the device is gone */
                sas_phy_disconnected(sas_phy);
@@ -572,7 +587,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
                sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
                break;
        default:
-               ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
+               ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __func__,
                            phy_id, sb_opcode);
                ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
                            edb, dl->opcode);
@@ -639,7 +654,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 
        if (status != 0) {
                ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
-                           __FUNCTION__, phy_id, status);
+                           __func__, phy_id, status);
                goto out;
        }
 
@@ -648,7 +663,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
                asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
                asd_turn_led(asd_ha, phy_id, 0);
                asd_control_led(asd_ha, phy_id, 0);
-               ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
+               ASD_DPRINTK("%s: disable phy%d\n", __func__, phy_id);
                break;
 
        case ENABLE_PHY:
@@ -658,40 +673,40 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
                        get_lrate_mode(phy, oob_mode);
                        asd_turn_led(asd_ha, phy_id, 1);
                        ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
-                                   __FUNCTION__, phy_id,phy->sas_phy.linkrate,
+                                   __func__, phy_id,phy->sas_phy.linkrate,
                                    phy->sas_phy.iproto);
                } else if (oob_status & CURRENT_SPINUP_HOLD) {
                        asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
                        asd_turn_led(asd_ha, phy_id, 1);
-                       ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
+                       ASD_DPRINTK("%s: phy%d, spinup hold\n", __func__,
                                    phy_id);
                } else if (oob_status & CURRENT_ERR_MASK) {
                        asd_turn_led(asd_ha, phy_id, 0);
                        ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
-                                   __FUNCTION__, phy_id, oob_status);
+                                   __func__, phy_id, oob_status);
                } else if (oob_status & (CURRENT_HOT_PLUG_CNCT
                                         | CURRENT_DEVICE_PRESENT))  {
                        asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
                        asd_turn_led(asd_ha, phy_id, 1);
                        ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
-                                   __FUNCTION__, phy_id);
+                                   __func__, phy_id);
                } else {
                        asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
                        asd_turn_led(asd_ha, phy_id, 0);
                        ASD_DPRINTK("%s: phy%d: no device present: "
                                    "oob_status:0x%x\n",
-                                   __FUNCTION__, phy_id, oob_status);
+                                   __func__, phy_id, oob_status);
                }
                break;
        case RELEASE_SPINUP_HOLD:
        case PHY_NO_OP:
        case EXECUTE_HARD_RESET:
-               ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
+               ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __func__,
                            phy_id, control_phy->sub_func);
                /* XXX finish */
                break;
        default:
-               ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
+               ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __func__,
                            phy_id, control_phy->sub_func);
                break;
        }
@@ -699,7 +714,7 @@ out:
        asd_ascb_free(ascb);
 }
 
-static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
+static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
 {
        /* disable all speeds, then enable defaults */
        *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS
@@ -778,12 +793,12 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
 
                /* initiator port settings are in the hi nibble */
                if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
-                       control_phy->port_type = SAS_PROTO_ALL << 4;
+                       control_phy->port_type = SAS_PROTOCOL_ALL << 4;
                else if (phy->sas_phy.role == PHY_ROLE_TARGET)
-                       control_phy->port_type = SAS_PROTO_ALL;
+                       control_phy->port_type = SAS_PROTOCOL_ALL;
                else
                        control_phy->port_type =
-                               (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
+                               (SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL;
 
                /* link reset retries, this should be nominal */
                control_phy->link_reset_retries = 10;
@@ -804,6 +819,8 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
 
 /* ---------- INITIATE LINK ADM TASK ---------- */
 
+#if 0
+
 static void link_adm_tasklet_complete(struct asd_ascb *ascb,
                                      struct done_list_struct *dl)
 {
@@ -836,6 +853,8 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
        ascb->tasklet_complete = link_adm_tasklet_complete;
 }
 
+#endif  /*  0  */
+
 /* ---------- SCB timer ---------- */
 
 /**