Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
authorDavid Howells <dhowells@redhat.com>
Wed, 6 Dec 2006 15:01:18 +0000 (15:01 +0000)
committerDavid Howells <dhowells@warthog.cambridge.redhat.com>
Wed, 6 Dec 2006 15:01:18 +0000 (15:01 +0000)
Conflicts:

drivers/pcmcia/ds.c

Fix up merge failures with Linus's head and fix new compile failures.

Signed-Off-By: David Howells <dhowells@redhat.com>
1  2 
drivers/char/pcmcia/synclink_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/pcmcia/ds.c
drivers/scsi/ipr.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_scan.c
include/scsi/libsas.h

@@@ -421,7 -421,7 +421,7 @@@ static irqreturn_t mgslpc_isr(int irq, 
  /*
   * Bottom half interrupt handlers
   */
 -static void bh_handler(void* Context);
 +static void bh_handler(struct work_struct *work);
  static void bh_transmit(MGSLPC_INFO *info);
  static void bh_status(MGSLPC_INFO *info);
  
@@@ -547,7 -547,7 +547,7 @@@ static int mgslpc_probe(struct pcmcia_d
  
      memset(info, 0, sizeof(MGSLPC_INFO));
      info->magic = MGSLPC_MAGIC;
 -    INIT_WORK(&info->task, bh_handler, info);
 +    INIT_WORK(&info->task, bh_handler);
      info->max_frame_size = 4096;
      info->close_delay = 5*HZ/10;
      info->closing_wait = 30*HZ;
@@@ -604,17 -604,10 +604,10 @@@ static int mgslpc_config(struct pcmcia_
      if (debug_level >= DEBUG_LEVEL_INFO)
            printk("mgslpc_config(0x%p)\n", link);
  
-     /* read CONFIG tuple to find its configuration registers */
-     tuple.DesiredTuple = CISTPL_CONFIG;
      tuple.Attributes = 0;
      tuple.TupleData = buf;
      tuple.TupleDataMax = sizeof(buf);
      tuple.TupleOffset = 0;
-     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
-     CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
-     link->conf.ConfigBase = parse.config.base;
-     link->conf.Present = parse.config.rmask[0];
  
      /* get CIS configuration entry */
  
@@@ -842,9 -835,9 +835,9 @@@ static int bh_action(MGSLPC_INFO *info
        return rc;
  }
  
 -static void bh_handler(void* Context)
 +static void bh_handler(struct work_struct *work)
  {
 -      MGSLPC_INFO *info = (MGSLPC_INFO*)Context;
 +      MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task);
        int action;
  
        if (!info)
@@@ -332,7 -332,6 +332,7 @@@ static irqreturn_t xirc2ps_interrupt(in
   */
  
  typedef struct local_info_t {
 +      struct net_device       *dev;
        struct pcmcia_device    *p_dev;
      dev_node_t node;
      struct net_device_stats stats;
   */
  static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
  static void do_tx_timeout(struct net_device *dev);
 -static void xirc2ps_tx_timeout_task(void *data);
 +static void xirc2ps_tx_timeout_task(struct work_struct *work);
  static struct net_device_stats *do_get_stats(struct net_device *dev);
  static void set_addresses(struct net_device *dev);
  static void set_multicast_list(struct net_device *dev);
@@@ -568,7 -567,6 +568,7 @@@ xirc2ps_probe(struct pcmcia_device *lin
      if (!dev)
            return -ENOMEM;
      local = netdev_priv(dev);
 +    local->dev = dev;
      local->p_dev = link;
      link->priv = dev;
  
  #ifdef HAVE_TX_TIMEOUT
      dev->tx_timeout = do_tx_timeout;
      dev->watchdog_timeo = TX_TIMEOUT;
 -    INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev);
 +    INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task);
  #endif
  
      return xirc2ps_config(link);
@@@ -709,22 -707,11 +709,11 @@@ set_card_type(struct pcmcia_device *lin
   * Returns: true if this is a CE2
   */
  static int
- has_ce2_string(struct pcmcia_device * link)
+ has_ce2_string(struct pcmcia_device * p_dev)
  {
-     tuple_t tuple;
-     cisparse_t parse;
-     u_char buf[256];
-     tuple.Attributes = 0;
-     tuple.TupleData = buf;
-     tuple.TupleDataMax = 254;
-     tuple.TupleOffset = 0;
-     tuple.DesiredTuple = CISTPL_VERS_1;
-     if (!first_tuple(link, &tuple, &parse) && parse.version_1.ns > 2) {
-       if (strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2"))
-           return 1;
-     }
-     return 0;
+       if (p_dev->prod_id[2] && strstr(p_dev->prod_id[2], "CE2"))
+               return 1;
+       return 0;
  }
  
  /****************
@@@ -794,13 -781,6 +783,6 @@@ xirc2ps_config(struct pcmcia_device * l
        goto failure;
      }
  
-     /* get configuration stuff */
-     tuple.DesiredTuple = CISTPL_CONFIG;
-     if ((err=first_tuple(link, &tuple, &parse)))
-       goto cis_error;
-     link->conf.ConfigBase = parse.config.base;
-     link->conf.Present =    parse.config.rmask[0];
      /* get the ethernet address from the CIS */
      tuple.DesiredTuple = CISTPL_FUNCE;
      for (err = first_tuple(link, &tuple, &parse); !err;
      xirc2ps_release(link);
      return -ENODEV;
  
-   cis_error:
-     printk(KNOT_XIRC "unable to parse CIS\n");
    failure:
      return -ENODEV;
  } /* xirc2ps_config */
@@@ -1346,11 -1324,9 +1326,11 @@@ xirc2ps_interrupt(int irq, void *dev_id
  /*====================================================================*/
  
  static void
 -xirc2ps_tx_timeout_task(void *data)
 +xirc2ps_tx_timeout_task(struct work_struct *work)
  {
 -    struct net_device *dev = data;
 +      local_info_t *local =
 +              container_of(work, local_info_t, tx_timeout_task);
 +      struct net_device *dev = local->dev;
      /* reset the card */
      do_reset(dev,1);
      dev->trans_start = jiffies;
diff --combined drivers/pcmcia/ds.c
@@@ -231,65 -231,6 +231,6 @@@ static void pcmcia_check_driver(struct 
  }
  
  
- #ifdef CONFIG_PCMCIA_LOAD_CIS
- /**
-  * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
-  * @dev - the pcmcia device which needs a CIS override
-  * @filename - requested filename in /lib/firmware/
-  *
-  * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
-  * the one provided by the card is broken. The firmware files reside in
-  * /lib/firmware/ in userspace.
-  */
- static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
- {
-       struct pcmcia_socket *s = dev->socket;
-       const struct firmware *fw;
-       char path[20];
-       int ret=-ENOMEM;
-       cisdump_t *cis;
-       if (!filename)
-               return -EINVAL;
-       ds_dbg(1, "trying to load firmware %s\n", filename);
-       if (strlen(filename) > 14)
-               return -EINVAL;
-       snprintf(path, 20, "%s", filename);
-       if (request_firmware(&fw, path, &dev->dev) == 0) {
-               if (fw->size >= CISTPL_MAX_CIS_SIZE)
-                       goto release;
-               cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
-               if (!cis)
-                       goto release;
-               cis->Length = fw->size + 1;
-               memcpy(cis->Data, fw->data, fw->size);
-               if (!pcmcia_replace_cis(s, cis))
-                       ret = 0;
-       }
-  release:
-       release_firmware(fw);
-       return (ret);
- }
- #else /* !CONFIG_PCMCIA_LOAD_CIS */
- static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
- {
-       return -ENODEV;
- }
- #endif
  /*======================================================================*/
  
  
@@@ -309,6 -250,8 +250,8 @@@ int pcmcia_register_driver(struct pcmci
        driver->drv.bus = &pcmcia_bus_type;
        driver->drv.owner = driver->owner;
  
+       ds_dbg(3, "registering driver %s\n", driver->drv.name);
        return driver_register(&driver->drv);
  }
  EXPORT_SYMBOL(pcmcia_register_driver);
   */
  void pcmcia_unregister_driver(struct pcmcia_driver *driver)
  {
+       ds_dbg(3, "unregistering driver %s\n", driver->drv.name);
        driver_unregister(&driver->drv);
  }
  EXPORT_SYMBOL(pcmcia_unregister_driver);
@@@ -343,23 -287,27 +287,27 @@@ void pcmcia_put_dev(struct pcmcia_devic
  static void pcmcia_release_function(struct kref *ref)
  {
        struct config_t *c = container_of(ref, struct config_t, ref);
+       ds_dbg(1, "releasing config_t\n");
        kfree(c);
  }
  
  static void pcmcia_release_dev(struct device *dev)
  {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-       ds_dbg(1, "releasing dev %p\n", p_dev);
+       ds_dbg(1, "releasing device %s\n", p_dev->dev.bus_id);
        pcmcia_put_socket(p_dev->socket);
        kfree(p_dev->devname);
        kref_put(&p_dev->function_config->ref, pcmcia_release_function);
        kfree(p_dev);
  }
  
- static void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
+ static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc)
  {
        if (!s->pcmcia_state.device_add_pending) {
+               ds_dbg(1, "scheduling to add %s secondary"
+                      " device to %d\n", mfc ? "mfc" : "pfc", s->sock);
                s->pcmcia_state.device_add_pending = 1;
+               s->pcmcia_state.mfc_pfc = mfc;
                schedule_work(&s->device_add);
        }
        return;
@@@ -371,6 -319,7 +319,7 @@@ static int pcmcia_device_probe(struct d
        struct pcmcia_driver *p_drv;
        struct pcmcia_device_id *did;
        struct pcmcia_socket *s;
+       cistpl_config_t cis_config;
        int ret = 0;
  
        dev = get_device(dev);
        p_drv = to_pcmcia_drv(dev->driver);
        s = p_dev->socket;
  
+       ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id,
+              p_drv->drv.name);
        if ((!p_drv->probe) || (!p_dev->function_config) ||
            (!try_module_get(p_drv->owner))) {
                ret = -EINVAL;
                goto put_dev;
        }
  
+       /* set up some more device information */
+       ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG,
+                               &cis_config);
+       if (!ret) {
+               p_dev->conf.ConfigBase = cis_config.base;
+               p_dev->conf.Present = cis_config.rmask[0];
+       } else {
+               printk(KERN_INFO "pcmcia: could not parse base and rmask0 of CIS\n");
+               p_dev->conf.ConfigBase = 0;
+               p_dev->conf.Present = 0;
+       }
        ret = p_drv->probe(p_dev);
-       if (ret)
+       if (ret) {
+               ds_dbg(1, "binding %s to %s failed with %d\n",
+                      p_dev->dev.bus_id, p_drv->drv.name, ret);
                goto put_module;
+       }
  
        /* handle pseudo multifunction devices:
         * there are at most two pseudo multifunction devices.
        did = p_dev->dev.driver_data;
        if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
            (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
-               pcmcia_add_pseudo_device(p_dev->socket);
+               pcmcia_add_device_later(p_dev->socket, 0);
  
   put_module:
        if (ret)
@@@ -421,8 -388,8 +388,8 @@@ static void pcmcia_card_remove(struct p
        struct pcmcia_device    *tmp;
        unsigned long           flags;
  
-       ds_dbg(2, "unbind_request(%d)\n", s->sock);
+       ds_dbg(2, "pcmcia_card_remove(%d) %s\n", s->sock,
+              leftover ? leftover->devname : "");
  
        if (!leftover)
                s->device_count = 0;
                p_dev->_removed=1;
                spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
  
+               ds_dbg(2, "unregistering device %s\n", p_dev->dev.bus_id);
                device_unregister(&p_dev->dev);
        }
  
@@@ -455,6 -423,8 +423,8 @@@ static int pcmcia_device_remove(struct 
        p_dev = to_pcmcia_dev(dev);
        p_drv = to_pcmcia_drv(dev->driver);
  
+       ds_dbg(1, "removing device %s\n", p_dev->dev.bus_id);
        /* If we're removing the primary module driving a
         * pseudo multi-function card, we need to unbind
         * all devices
@@@ -587,8 -557,10 +557,10 @@@ struct pcmcia_device * pcmcia_device_ad
  
        mutex_lock(&device_add_lock);
  
-       /* max of 2 devices per card */
-       if (s->device_count == 2)
+       ds_dbg(3, "adding device to %d, function %d\n", s->sock, function);
+       /* max of 4 devices per card */
+       if (s->device_count == 4)
                goto err_put;
  
        p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
        p_dev->socket = s;
        p_dev->device_no = (s->device_count++);
        p_dev->func   = function;
-       if (s->functions <= function)
-               s->functions = function + 1;
  
        p_dev->dev.bus = &pcmcia_bus_type;
        p_dev->dev.parent = s->dev.dev;
        if (!p_dev->devname)
                goto err_free;
        sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
+       ds_dbg(3, "devname is %s\n", p_dev->devname);
  
-       /* compat */
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
  
        /*
        spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
  
        if (!p_dev->function_config) {
+               ds_dbg(3, "creating config_t for %s\n", p_dev->dev.bus_id);
                p_dev->function_config = kzalloc(sizeof(struct config_t),
                                                 GFP_KERNEL);
                if (!p_dev->function_config)
@@@ -674,11 -645,16 +645,16 @@@ static int pcmcia_card_add(struct pcmci
        unsigned int no_funcs, i;
        int ret = 0;
  
-       if (!(s->resource_setup_done))
+       if (!(s->resource_setup_done)) {
+               ds_dbg(3, "no resources available, delaying card_add\n");
                return -EAGAIN; /* try again, but later... */
+       }
  
-       if (pcmcia_validate_mem(s))
+       if (pcmcia_validate_mem(s)) {
+               ds_dbg(3, "validating mem resources failed, "
+                      "delaying card_add\n");
                return -EAGAIN; /* try again, but later... */
+       }
  
        ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
        if (ret || !cisinfo.Chains) {
                no_funcs = mfc.nfn;
        else
                no_funcs = 1;
+       s->functions = no_funcs;
  
        for (i=0; i < no_funcs; i++)
                pcmcia_device_add(s, i);
  }
  
  
- static void pcmcia_delayed_add_pseudo_device(struct work_struct *work)
 -static void pcmcia_delayed_add_device(void *data)
++static void pcmcia_delayed_add_device(struct work_struct *work)
  {
 -      struct pcmcia_socket *s = data;
 +      struct pcmcia_socket *s =
 +              container_of(work, struct pcmcia_socket, device_add);
-       pcmcia_device_add(s, 0);
+       ds_dbg(1, "adding additional device to %d\n", s->sock);
+       pcmcia_device_add(s, s->pcmcia_state.mfc_pfc);
        s->pcmcia_state.device_add_pending = 0;
+       s->pcmcia_state.mfc_pfc = 0;
  }
  
  static int pcmcia_requery(struct device *dev, void * _data)
  {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
-       if (!p_dev->dev.driver)
+       if (!p_dev->dev.driver) {
+               ds_dbg(1, "update device information for %s\n",
+                      p_dev->dev.bus_id);
                pcmcia_device_query(p_dev);
+       }
  
        return 0;
  }
  
- static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
+ static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis)
  {
-       int no_devices=0;
+       int no_devices = 0;
        int ret = 0;
        unsigned long flags;
  
        /* must be called with skt_mutex held */
+       ds_dbg(0, "re-scanning socket %d\n", skt->sock);
        spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
        if (list_empty(&skt->devices_list))
-               no_devices=1;
+               no_devices = 1;
        spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
  
+       /* If this is because of a CIS override, start over */
+       if (new_cis && !no_devices)
+               pcmcia_card_remove(skt, NULL);
        /* if no devices were added for this socket yet because of
         * missing resource information or other trouble, we need to
         * do this now. */
-       if (no_devices) {
+       if (no_devices || new_cis) {
                ret = pcmcia_card_add(skt);
                if (ret)
                        return;
                printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n");
  }
  
+ #ifdef CONFIG_PCMCIA_LOAD_CIS
+ /**
+  * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
+  * @dev - the pcmcia device which needs a CIS override
+  * @filename - requested filename in /lib/firmware/
+  *
+  * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
+  * the one provided by the card is broken. The firmware files reside in
+  * /lib/firmware/ in userspace.
+  */
+ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
+ {
+       struct pcmcia_socket *s = dev->socket;
+       const struct firmware *fw;
+       char path[20];
+       int ret = -ENOMEM;
+       int no_funcs;
+       int old_funcs;
+       cisdump_t *cis;
+       cistpl_longlink_mfc_t mfc;
+       if (!filename)
+               return -EINVAL;
+       ds_dbg(1, "trying to load CIS file %s\n", filename);
+       if (strlen(filename) > 14) {
+               printk(KERN_WARNING "pcmcia: CIS filename is too long\n");
+               return -EINVAL;
+       }
+       snprintf(path, 20, "%s", filename);
+       if (request_firmware(&fw, path, &dev->dev) == 0) {
+               if (fw->size >= CISTPL_MAX_CIS_SIZE) {
+                       ret = -EINVAL;
+                       printk(KERN_ERR "pcmcia: CIS override is too big\n");
+                       goto release;
+               }
+               cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL);
+               if (!cis) {
+                       ret = -ENOMEM;
+                       goto release;
+               }
+               cis->Length = fw->size + 1;
+               memcpy(cis->Data, fw->data, fw->size);
+               if (!pcmcia_replace_cis(s, cis))
+                       ret = 0;
+               else {
+                       printk(KERN_ERR "pcmcia: CIS override failed\n");
+                       goto release;
+               }
+               /* update information */
+               pcmcia_device_query(dev);
+               /* does this cis override add or remove functions? */
+               old_funcs = s->functions;
+               if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
+                       no_funcs = mfc.nfn;
+               else
+                       no_funcs = 1;
+               s->functions = no_funcs;
+               if (old_funcs > no_funcs)
+                       pcmcia_card_remove(s, dev);
+               else if (no_funcs > old_funcs)
+                       pcmcia_add_device_later(s, 1);
+       }
+  release:
+       release_firmware(fw);
+       return (ret);
+ }
+ #else /* !CONFIG_PCMCIA_LOAD_CIS */
+ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
+ {
+       return -ENODEV;
+ }
+ #endif
  static inline int pcmcia_devmatch(struct pcmcia_device *dev,
                                  struct pcmcia_device_id *did)
  {
                 * after it has re-checked that there is no possible module
                 * with a prod_id/manf_id/card_id match.
                 */
+               ds_dbg(0, "skipping FUNC_ID match for %s until userspace "
+                      "interaction\n", dev->dev.bus_id);
                if (!dev->allow_func_id_match)
                        return 0;
        }
  
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
+               ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id);
                if (!dev->socket->fake_cis)
                        pcmcia_load_firmware(dev, did->cisfile);
  
@@@ -848,13 -929,21 +930,21 @@@ static int pcmcia_bus_match(struct devi
  
  #ifdef CONFIG_PCMCIA_IOCTL
        /* matching by cardmgr */
-       if (p_dev->cardmgr == p_drv)
+       if (p_dev->cardmgr == p_drv) {
+               ds_dbg(0, "cardmgr matched %s to %s\n", dev->bus_id,
+                      drv->name);
                return 1;
+       }
  #endif
  
        while (did && did->match_flags) {
-               if (pcmcia_devmatch(p_dev, did))
+               ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
+                      drv->name);
+               if (pcmcia_devmatch(p_dev, did)) {
+                       ds_dbg(0, "matched %s to %s\n", dev->bus_id,
+                              drv->name);
                        return 1;
+               }
                did++;
        }
  
@@@ -1045,6 -1134,8 +1135,8 @@@ static int pcmcia_dev_suspend(struct de
        struct pcmcia_driver *p_drv = NULL;
        int ret = 0;
  
+       ds_dbg(2, "suspending %s\n", dev->bus_id);
        if (dev->driver)
                p_drv = to_pcmcia_drv(dev->driver);
  
  
        if (p_drv->suspend) {
                ret = p_drv->suspend(p_dev);
-               if (ret)
+               if (ret) {
+                       printk(KERN_ERR "pcmcia: device %s (driver %s) did "
+                              "not want to go to sleep (%d)\n",
+                              p_dev->devname, p_drv->drv.name, ret);
                        goto out;
+               }
        }
  
-       if (p_dev->device_no == p_dev->func)
+       if (p_dev->device_no == p_dev->func) {
+               ds_dbg(2, "releasing configuration for %s\n", dev->bus_id);
                pcmcia_release_configuration(p_dev);
+       }
  
   out:
        if (!ret)
@@@ -1073,6 -1170,8 +1171,8 @@@ static int pcmcia_dev_resume(struct dev
          struct pcmcia_driver *p_drv = NULL;
        int ret = 0;
  
+       ds_dbg(2, "resuming %s\n", dev->bus_id);
        if (dev->driver)
                p_drv = to_pcmcia_drv(dev->driver);
  
                goto out;
  
        if (p_dev->device_no == p_dev->func) {
+               ds_dbg(2, "requesting configuration for %s\n", dev->bus_id);
                ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
                if (ret)
                        goto out;
@@@ -1121,12 -1221,14 +1222,14 @@@ static int pcmcia_bus_resume_callback(s
  
  static int pcmcia_bus_resume(struct pcmcia_socket *skt)
  {
+       ds_dbg(2, "resuming socket %d\n", skt->sock);
        bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
        return 0;
  }
  
  static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
  {
+       ds_dbg(2, "suspending socket %d\n", skt->sock);
        if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
                             pcmcia_bus_suspend_callback)) {
                pcmcia_bus_resume(skt);
@@@ -1247,7 -1349,7 +1350,7 @@@ static int __devinit pcmcia_bus_add_soc
        init_waitqueue_head(&socket->queue);
  #endif
        INIT_LIST_HEAD(&socket->devices_list);
-       INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device);
 -      INIT_WORK(&socket->device_add, pcmcia_delayed_add_device, socket);
++      INIT_WORK(&socket->device_add, pcmcia_delayed_add_device);
        memset(&socket->pcmcia_state, 0, sizeof(u8));
        socket->device_count = 0;
  
diff --combined drivers/scsi/ipr.c
@@@ -79,7 -79,6 +79,6 @@@
  #include <scsi/scsi_tcq.h>
  #include <scsi/scsi_eh.h>
  #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_transport.h>
  #include "ipr.h"
  
  /*
@@@ -98,7 -97,7 +97,7 @@@ static DEFINE_SPINLOCK(ipr_driver_lock)
  
  /* This table describes the differences between DMA controller chips */
  static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
-       { /* Gemstone, Citrine, and Obsidian */
+       { /* Gemstone, Citrine, Obsidian, and Obsidian-E */
                .mailbox = 0x0042C,
                .cache_line_size = 0x20,
                {
@@@ -135,6 -134,7 +134,7 @@@ static const struct ipr_chip_t ipr_chip
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
  };
@@@ -1249,19 -1249,23 +1249,23 @@@ static void ipr_log_array_error(struct 
  
  /**
   * ipr_log_hex_data - Log additional hex IOA error data.
+  * @ioa_cfg:  ioa config struct
   * @data:             IOA error data
   * @len:              data length
   *
   * Return value:
   *    none
   **/
- static void ipr_log_hex_data(u32 *data, int len)
+ static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len)
  {
        int i;
  
        if (len == 0)
                return;
  
+       if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL)
+               len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP);
        for (i = 0; i < len / 4; i += 4) {
                ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
                        be32_to_cpu(data[i]),
@@@ -1290,7 -1294,7 +1294,7 @@@ static void ipr_log_enhanced_dual_ioa_e
        ipr_err("%s\n", error->failure_reason);
        ipr_err("Remote Adapter VPD:\n");
        ipr_log_ext_vpd(&error->vpd);
-       ipr_log_hex_data(error->data,
+       ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
                          offsetof(struct ipr_hostrcb_type_17_error, data)));
@@@ -1315,12 -1319,225 +1319,225 @@@ static void ipr_log_dual_ioa_error(stru
        ipr_err("%s\n", error->failure_reason);
        ipr_err("Remote Adapter VPD:\n");
        ipr_log_vpd(&error->vpd);
-       ipr_log_hex_data(error->data,
+       ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
                          offsetof(struct ipr_hostrcb_type_07_error, data)));
  }
  
+ static const struct {
+       u8 active;
+       char *desc;
+ } path_active_desc[] = {
+       { IPR_PATH_NO_INFO, "Path" },
+       { IPR_PATH_ACTIVE, "Active path" },
+       { IPR_PATH_NOT_ACTIVE, "Inactive path" }
+ };
+ static const struct {
+       u8 state;
+       char *desc;
+ } path_state_desc[] = {
+       { IPR_PATH_STATE_NO_INFO, "has no path state information available" },
+       { IPR_PATH_HEALTHY, "is healthy" },
+       { IPR_PATH_DEGRADED, "is degraded" },
+       { IPR_PATH_FAILED, "is failed" }
+ };
+ /**
+  * ipr_log_fabric_path - Log a fabric path error
+  * @hostrcb:  hostrcb struct
+  * @fabric:           fabric descriptor
+  *
+  * Return value:
+  *    none
+  **/
+ static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb,
+                               struct ipr_hostrcb_fabric_desc *fabric)
+ {
+       int i, j;
+       u8 path_state = fabric->path_state;
+       u8 active = path_state & IPR_PATH_ACTIVE_MASK;
+       u8 state = path_state & IPR_PATH_STATE_MASK;
+       for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) {
+               if (path_active_desc[i].active != active)
+                       continue;
+               for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) {
+                       if (path_state_desc[j].state != state)
+                               continue;
+                       if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port);
+                       } else if (fabric->cascaded_expander == 0xff) {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port, fabric->phy);
+                       } else if (fabric->phy == 0xff) {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port, fabric->cascaded_expander);
+                       } else {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
+                       }
+                       return;
+               }
+       }
+       ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state,
+               fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
+ }
+ static const struct {
+       u8 type;
+       char *desc;
+ } path_type_desc[] = {
+       { IPR_PATH_CFG_IOA_PORT, "IOA port" },
+       { IPR_PATH_CFG_EXP_PORT, "Expander port" },
+       { IPR_PATH_CFG_DEVICE_PORT, "Device port" },
+       { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" }
+ };
+ static const struct {
+       u8 status;
+       char *desc;
+ } path_status_desc[] = {
+       { IPR_PATH_CFG_NO_PROB, "Functional" },
+       { IPR_PATH_CFG_DEGRADED, "Degraded" },
+       { IPR_PATH_CFG_FAILED, "Failed" },
+       { IPR_PATH_CFG_SUSPECT, "Suspect" },
+       { IPR_PATH_NOT_DETECTED, "Missing" },
+       { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" }
+ };
+ static const char *link_rate[] = {
+       "unknown",
+       "disabled",
+       "phy reset problem",
+       "spinup hold",
+       "port selector",
+       "unknown",
+       "unknown",
+       "unknown",
+       "1.5Gbps",
+       "3.0Gbps",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown"
+ };
+ /**
+  * ipr_log_path_elem - Log a fabric path element.
+  * @hostrcb:  hostrcb struct
+  * @cfg:              fabric path element struct
+  *
+  * Return value:
+  *    none
+  **/
+ static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb,
+                             struct ipr_hostrcb_config_element *cfg)
+ {
+       int i, j;
+       u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK;
+       u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK;
+       if (type == IPR_PATH_CFG_NOT_EXIST)
+               return;
+       for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) {
+               if (path_type_desc[i].type != type)
+                       continue;
+               for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) {
+                       if (path_status_desc[j].status != status)
+                               continue;
+                       if (type == IPR_PATH_CFG_IOA_PORT) {
+                               ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n",
+                                            path_status_desc[j].desc, path_type_desc[i].desc,
+                                            cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                            be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                       } else {
+                               if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) {
+                                       ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n",
+                                                    path_status_desc[j].desc, path_type_desc[i].desc,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               } else if (cfg->cascaded_expander == 0xff) {
+                                       ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, "
+                                                    "WWN=%08X%08X\n", path_status_desc[j].desc,
+                                                    path_type_desc[i].desc, cfg->phy,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               } else if (cfg->phy == 0xff) {
+                                       ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, "
+                                                    "WWN=%08X%08X\n", path_status_desc[j].desc,
+                                                    path_type_desc[i].desc, cfg->cascaded_expander,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               } else {
+                                       ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s "
+                                                    "WWN=%08X%08X\n", path_status_desc[j].desc,
+                                                    path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               }
+                       }
+                       return;
+               }
+       }
+       ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s "
+                    "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy,
+                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+ }
+ /**
+  * ipr_log_fabric_error - Log a fabric error.
+  * @ioa_cfg:  ioa config struct
+  * @hostrcb:  hostrcb struct
+  *
+  * Return value:
+  *    none
+  **/
+ static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
+                                struct ipr_hostrcb *hostrcb)
+ {
+       struct ipr_hostrcb_type_20_error *error;
+       struct ipr_hostrcb_fabric_desc *fabric;
+       struct ipr_hostrcb_config_element *cfg;
+       int i, add_len;
+       error = &hostrcb->hcam.u.error.u.type_20_error;
+       error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       ipr_hcam_err(hostrcb, "%s\n", error->failure_reason);
+       add_len = be32_to_cpu(hostrcb->hcam.length) -
+               (offsetof(struct ipr_hostrcb_error, u) +
+                offsetof(struct ipr_hostrcb_type_20_error, desc));
+       for (i = 0, fabric = error->desc; i < error->num_entries; i++) {
+               ipr_log_fabric_path(hostrcb, fabric);
+               for_each_fabric_cfg(fabric, cfg)
+                       ipr_log_path_elem(hostrcb, cfg);
+               add_len -= be16_to_cpu(fabric->length);
+               fabric = (struct ipr_hostrcb_fabric_desc *)
+                       ((unsigned long)fabric + be16_to_cpu(fabric->length));
+       }
+       ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len);
+ }
  /**
   * ipr_log_generic_error - Log an adapter error.
   * @ioa_cfg:  ioa config struct
  static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
                                  struct ipr_hostrcb *hostrcb)
  {
-       ipr_log_hex_data(hostrcb->hcam.u.raw.data,
+       ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data,
                         be32_to_cpu(hostrcb->hcam.length));
  }
  
@@@ -1394,13 -1611,7 +1611,7 @@@ static void ipr_handle_log_data(struct 
        if (!ipr_error_table[error_index].log_hcam)
                return;
  
-       if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
-               ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
-                          "%s\n", ipr_error_table[error_index].error);
-       } else {
-               dev_err(&ioa_cfg->pdev->dev, "%s\n",
-                       ipr_error_table[error_index].error);
-       }
+       ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error);
  
        /* Set indication we have logged an error */
        ioa_cfg->errors_logged++;
        case IPR_HOST_RCB_OVERLAY_ID_17:
                ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb);
                break;
+       case IPR_HOST_RCB_OVERLAY_ID_20:
+               ipr_log_fabric_error(ioa_cfg, hostrcb);
+               break;
        case IPR_HOST_RCB_OVERLAY_ID_1:
        case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
        default:
@@@ -2093,7 -2307,7 +2307,7 @@@ static void ipr_release_dump(struct kre
  
  /**
   * ipr_worker_thread - Worker thread
 - * @data:             ioa config struct
 + * @work:             ioa config struct
   *
   * Called at task level from a work thread. This function takes care
   * of adding and removing device from the mid-layer as configuration
   * Return value:
   *    nothing
   **/
 -static void ipr_worker_thread(void *data)
 +static void ipr_worker_thread(struct work_struct *work)
  {
        unsigned long lock_flags;
        struct ipr_resource_entry *res;
        struct scsi_device *sdev;
        struct ipr_dump *dump;
 -      struct ipr_ioa_cfg *ioa_cfg = data;
 +      struct ipr_ioa_cfg *ioa_cfg =
 +              container_of(work, struct ipr_ioa_cfg, work_q);
        u8 bus, target, lun;
        int did_work;
  
@@@ -2970,7 -3183,6 +3184,6 @@@ static int ipr_alloc_dump(struct ipr_io
        struct ipr_dump *dump;
        unsigned long lock_flags = 0;
  
-       ENTER;
        dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL);
  
        if (!dump) {
        }
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
  
-       LEAVE;
        return 0;
  }
  
@@@ -3574,6 -3785,12 +3786,12 @@@ static int ipr_sata_reset(struct ata_po
  
        ENTER;
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
        res = sata_port->res;
        if (res) {
                rc = ipr_device_reset(ioa_cfg, res);
@@@ -3637,6 -3854,10 +3855,10 @@@ static int __ipr_eh_dev_reset(struct sc
                if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
                        if (ipr_cmd->scsi_cmd)
                                ipr_cmd->done = ipr_scsi_eh_done;
+                       if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
+                               ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
+                               ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
+                       }
                }
        }
  
@@@ -3771,7 -3992,7 +3993,7 @@@ static int ipr_cancel_op(struct scsi_cm
         */
        if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead)
                return FAILED;
-       if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+       if (!res || !ipr_is_gscsi(res))
                return FAILED;
  
        list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
@@@ -4616,7 -4837,7 +4838,7 @@@ static int ipr_queuecommand(struct scsi
   * Return value:
   *    0 on success / other on failure
   **/
- int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
  {
        struct ipr_resource_entry *res;
  
@@@ -4649,40 -4870,6 +4871,6 @@@ static const char * ipr_ioa_info(struc
        return buffer;
  }
  
- /**
-  * ipr_scsi_timed_out - Handle scsi command timeout
-  * @scsi_cmd: scsi command struct
-  *
-  * Return value:
-  *    EH_NOT_HANDLED
-  **/
- enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd)
- {
-       struct ipr_ioa_cfg *ioa_cfg;
-       struct ipr_cmnd *ipr_cmd;
-       unsigned long flags;
-       ENTER;
-       spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
-       ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
-       list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
-               if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) {
-                       ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
-                       ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
-       LEAVE;
-       return EH_NOT_HANDLED;
- }
- static struct scsi_transport_template ipr_transport_template = {
-       .eh_timed_out = ipr_scsi_timed_out
- };
  static struct scsi_host_template driver_template = {
        .module = THIS_MODULE,
        .name = "IPR",
@@@ -4777,6 -4964,12 +4965,12 @@@ static void ipr_ata_post_internal(struc
        unsigned long flags;
  
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+       }
        list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
                if (ipr_cmd->qc == qc) {
                        ipr_device_reset(ioa_cfg, sata_port->res);
@@@ -6833,6 -7026,7 +7027,7 @@@ static int __devinit ipr_alloc_mem(stru
  
                ioa_cfg->hostrcb[i]->hostrcb_dma =
                        ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam);
+               ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg;
                list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
        }
  
@@@ -6927,7 -7121,7 +7122,7 @@@ static void __devinit ipr_init_ioa_cfg(
        INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
        INIT_LIST_HEAD(&ioa_cfg->free_res_q);
        INIT_LIST_HEAD(&ioa_cfg->used_res_q);
 -      INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg);
 +      INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
        init_waitqueue_head(&ioa_cfg->reset_wait_q);
        ioa_cfg->sdt_state = INACTIVE;
        if (ipr_enable_cache)
@@@ -7018,7 -7212,6 +7213,6 @@@ static int __devinit ipr_probe_ioa(stru
  
        ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
        memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
-       host->transportt = &ipr_transport_template;
        ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
                      sata_port_info.flags, &ipr_sata_ops);
  
@@@ -7352,12 -7545,24 +7546,24 @@@ static struct pci_device_id ipr_pci_tab
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
                0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F,
                0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F,
+               0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
        { }
  };
  MODULE_DEVICE_TABLE(pci, ipr_pci_table);
@@@ -65,11 -65,9 +65,11 @@@ void sas_hash_addr(u8 *hashed, const u
  
  /* ---------- HA events ---------- */
  
 -void sas_hae_reset(void *data)
 +void sas_hae_reset(struct work_struct *work)
  {
 -      struct sas_ha_struct *ha = data;
 +      struct sas_ha_event *ev =
 +              container_of(work, struct sas_ha_event, work);
 +      struct sas_ha_struct *ha = ev->ha;
  
        sas_begin_event(HAE_RESET, &ha->event_lock,
                        &ha->pending);
@@@ -114,6 -112,8 +114,8 @@@ int sas_register_ha(struct sas_ha_struc
                }
        }
  
+       INIT_LIST_HEAD(&sas_ha->eh_done_q);
        return 0;
  
  Undo_ports:
@@@ -144,7 -144,7 +146,7 @@@ static int sas_get_linkerrors(struct sa
        return sas_smp_get_phy_events(phy);
  }
  
static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
+ int sas_phy_reset(struct sas_phy *phy, int hard_reset)
  {
        int ret;
        enum phy_func reset_type;
@@@ -708,10 -708,10 +708,10 @@@ static int qla4xxx_cmd_wait(struct scsi
  }
  
  /**
-  * qla4010_soft_reset - performs soft reset.
+  * qla4xxx_soft_reset - performs soft reset.
   * @ha: Pointer to host adapter structure.
   **/
static int qla4010_soft_reset(struct scsi_qla_host *ha)
int qla4xxx_soft_reset(struct scsi_qla_host *ha)
  {
        uint32_t max_wait_time;
        unsigned long flags = 0;
        return status;
  }
  
- /**
-  * qla4xxx_topcat_reset - performs hard reset of TopCat Chip.
-  * @ha: Pointer to host adapter structure.
-  **/
- static int qla4xxx_topcat_reset(struct scsi_qla_host *ha)
- {
-       unsigned long flags;
-       ql4xxx_lock_nvram(ha);
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       writel(set_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
-       readl(isp_gp_out(ha));
-       mdelay(1);
-       writel(clr_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
-       readl(isp_gp_out(ha));
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       mdelay(2523);
-       ql4xxx_unlock_nvram(ha);
-       return QLA_SUCCESS;
- }
  /**
   * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
   * @ha: Pointer to host adapter structure.
@@@ -866,26 -843,6 +843,6 @@@ static void qla4xxx_flush_active_srbs(s
  
  }
  
- /**
-  * qla4xxx_hard_reset - performs HBA Hard Reset
-  * @ha: Pointer to host adapter structure.
-  **/
- static int qla4xxx_hard_reset(struct scsi_qla_host *ha)
- {
-       /* The QLA4010 really doesn't have an equivalent to a hard reset */
-       qla4xxx_flush_active_srbs(ha);
-       if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
-               int status = QLA_ERROR;
-               if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
-                   (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
-                   (qla4010_soft_reset(ha) == QLA_SUCCESS))
-                       status = QLA_SUCCESS;
-               return status;
-       } else
-               return qla4010_soft_reset(ha);
- }
  /**
   * qla4xxx_recover_adapter - recovers adapter after a fatal error
   * @ha: Pointer to host adapter structure.
@@@ -919,18 -876,11 +876,11 @@@ static int qla4xxx_recover_adapter(stru
        if (status == QLA_SUCCESS) {
                DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
                              ha->host_no, __func__));
-               status = qla4xxx_soft_reset(ha);
-       }
-       /* FIXMEkaren: Do we want to keep interrupts enabled and process
-          AENs after soft reset */
-       /* If firmware (SOFT) reset failed, or if all outstanding
-        * commands have not returned, then do a HARD reset.
-        */
-       if (status == QLA_ERROR) {
-               DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n",
-                             ha->host_no, __func__));
-               status = qla4xxx_hard_reset(ha);
+               qla4xxx_flush_active_srbs(ha);
+               if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+                       status = qla4xxx_soft_reset(ha);
+               else
+                       status = QLA_ERROR;
        }
  
        /* Flush any pending ddb changed AENs */
   * the mid-level tries to sleep when it reaches the driver threshold
   * "host->can_queue". This can cause a panic if we were in our interrupt code.
   **/
 -static void qla4xxx_do_dpc(void *data)
 +static void qla4xxx_do_dpc(struct work_struct *work)
  {
 -      struct scsi_qla_host *ha = (struct scsi_qla_host *) data;
 +      struct scsi_qla_host *ha =
 +              container_of(work, struct scsi_qla_host, dpc_work);
        struct ddb_entry *ddb_entry, *dtemp;
  
-       DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n",
-                     ha->host_no, __func__));
-       DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n",
-                     ha->host_no, __func__, ha->flags));
-       DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n",
-                     ha->host_no, __func__, ha->dpc_flags));
+       DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
+               "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+               ha->host_no, __func__, ha->flags, ha->dpc_flags));
  
        /* Initialization not yet finished. Don't do anything yet. */
        if (!test_bit(AF_INIT_DONE, &ha->flags))
            test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
-               if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags))
-                       /*
-                        * dg 09/23 Never initialize ddb list
-                        * once we up and running
-                        * qla4xxx_recover_adapter(ha,
-                        *    REBUILD_DDB_LIST);
-                        */
-                       qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
-               if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+               if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+                       test_bit(DPC_RESET_HA, &ha->dpc_flags))
                        qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
  
                if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
@@@ -1123,7 -1060,8 +1061,8 @@@ static void qla4xxx_free_adapter(struc
                destroy_workqueue(ha->dpc_thread);
  
        /* Issue Soft Reset to put firmware in unknown state */
-       qla4xxx_soft_reset(ha);
+       if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+               qla4xxx_soft_reset(ha);
  
        /* Remove timer thread, if present */
        if (ha->timer_active)
@@@ -1262,7 -1200,6 +1201,6 @@@ static int __devinit qla4xxx_probe_adap
        init_waitqueue_head(&ha->mailbox_wait_queue);
  
        spin_lock_init(&ha->hardware_lock);
-       spin_lock_init(&ha->list_lock);
  
        /* Allocate dma buffers */
        if (qla4xxx_mem_alloc(ha)) {
                ret = -ENODEV;
                goto probe_failed;
        }
 -      INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc, ha);
 +      INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
  
        ret = request_irq(pdev->irq, qla4xxx_intr_handler,
                          SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha);
@@@ -1468,27 -1405,6 +1406,6 @@@ struct srb * qla4xxx_del_from_active_ar
        return srb;
  }
  
- /**
-  * qla4xxx_soft_reset - performs a SOFT RESET of hba.
-  * @ha: Pointer to host adapter structure.
-  **/
- int qla4xxx_soft_reset(struct scsi_qla_host *ha)
- {
-       DEBUG2(printk(KERN_WARNING "scsi%ld: %s: chip reset!\n", ha->host_no,
-                     __func__));
-       if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
-               int status = QLA_ERROR;
-               if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
-                   (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
-                   (qla4010_soft_reset(ha) == QLA_SUCCESS) )
-                       status = QLA_SUCCESS;
-               return status;
-       } else
-               return qla4010_soft_reset(ha);
- }
  /**
   * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
   * @ha: actual ha whose done queue will contain the comd returned by firmware.
@@@ -1687,6 -1603,12 +1604,12 @@@ static struct pci_device_id qla4xxx_pci
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
        },
+       {
+               .vendor         = PCI_VENDOR_ID_QLOGIC,
+               .device         = PCI_DEVICE_ID_QLOGIC_ISP4032,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+       },
        {0, 0},
  };
  MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
diff --combined drivers/scsi/scsi_scan.c
@@@ -29,7 -29,9 +29,9 @@@
  #include <linux/moduleparam.h>
  #include <linux/init.h>
  #include <linux/blkdev.h>
- #include <asm/semaphore.h>
+ #include <linux/delay.h>
+ #include <linux/kthread.h>
+ #include <linux/spinlock.h>
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_cmnd.h>
@@@ -87,6 -89,17 +89,17 @@@ module_param_named(max_luns, max_scsi_l
  MODULE_PARM_DESC(max_luns,
                 "last scsi LUN (should be between 1 and 2^32-1)");
  
+ #ifdef CONFIG_SCSI_SCAN_ASYNC
+ #define SCSI_SCAN_TYPE_DEFAULT "async"
+ #else
+ #define SCSI_SCAN_TYPE_DEFAULT "sync"
+ #endif
+ static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT;
+ module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
+ MODULE_PARM_DESC(scan, "sync, async or none");
  /*
   * max_scsi_report_luns: the maximum number of LUNS that will be
   * returned from the REPORT LUNS command. 8 times this value must
@@@ -108,6 -121,68 +121,68 @@@ MODULE_PARM_DESC(inq_timeout
                 "Timeout (in seconds) waiting for devices to answer INQUIRY."
                 " Default is 5. Some non-compliant devices need more.");
  
+ static DEFINE_SPINLOCK(async_scan_lock);
+ static LIST_HEAD(scanning_hosts);
+ struct async_scan_data {
+       struct list_head list;
+       struct Scsi_Host *shost;
+       struct completion prev_finished;
+ };
+ /**
+  * scsi_complete_async_scans - Wait for asynchronous scans to complete
+  *
+  * Asynchronous scans add themselves to the scanning_hosts list.  Once
+  * that list is empty, we know that the scans are complete.  Rather than
+  * waking up periodically to check the state of the list, we pretend to be
+  * a scanning task by adding ourselves at the end of the list and going to
+  * sleep.  When the task before us wakes us up, we take ourselves off the
+  * list and return.
+  */
+ int scsi_complete_async_scans(void)
+ {
+       struct async_scan_data *data;
+       do {
+               if (list_empty(&scanning_hosts))
+                       return 0;
+               /* If we can't get memory immediately, that's OK.  Just
+                * sleep a little.  Even if we never get memory, the async
+                * scans will finish eventually.
+                */
+               data = kmalloc(sizeof(*data), GFP_KERNEL);
+               if (!data)
+                       msleep(1);
+       } while (!data);
+       data->shost = NULL;
+       init_completion(&data->prev_finished);
+       spin_lock(&async_scan_lock);
+       /* Check that there's still somebody else on the list */
+       if (list_empty(&scanning_hosts))
+               goto done;
+       list_add_tail(&data->list, &scanning_hosts);
+       spin_unlock(&async_scan_lock);
+       printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n");
+       wait_for_completion(&data->prev_finished);
+       spin_lock(&async_scan_lock);
+       list_del(&data->list);
+  done:
+       spin_unlock(&async_scan_lock);
+       kfree(data);
+       return 0;
+ }
+ #ifdef MODULE
+ /* Only exported for the benefit of scsi_wait_scan */
+ EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
+ #endif
  /**
   * scsi_unlock_floptical - unlock device via a special MODE SENSE command
   * @sdev:     scsi device to send command to
@@@ -362,10 -437,9 +437,10 @@@ static struct scsi_target *scsi_alloc_t
        goto retry;
  }
  
 -static void scsi_target_reap_usercontext(void *data)
 +static void scsi_target_reap_usercontext(struct work_struct *work)
  {
 -      struct scsi_target *starget = data;
 +      struct scsi_target *starget =
 +              container_of(work, struct scsi_target, ew.work);
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        unsigned long flags;
  
@@@ -401,7 -475,7 +476,7 @@@ void scsi_target_reap(struct scsi_targe
                starget->state = STARGET_DEL;
                spin_unlock_irqrestore(shost->host_lock, flags);
                execute_in_process_context(scsi_target_reap_usercontext,
 -                                         starget, &starget->ew);
 +                                         &starget->ew);
                return;
  
        }
@@@ -620,7 -694,7 +695,7 @@@ static int scsi_probe_lun(struct scsi_d
   *     SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
   **/
  static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
-               int *bflags)
+               int *bflags, int async)
  {
        /*
         * XXX do not save the inquiry, since it can change underneath us,
         * register it and tell the rest of the kernel
         * about it.
         */
-       if (scsi_sysfs_add_sdev(sdev) != 0)
+       if (!async && scsi_sysfs_add_sdev(sdev) != 0)
                return SCSI_SCAN_NO_RESPONSE;
  
        return SCSI_SCAN_LUN_PRESENT;
@@@ -975,7 -1049,7 +1050,7 @@@ static int scsi_probe_and_add_lun(struc
                goto out_free_result;
        }
  
-       res = scsi_add_lun(sdev, result, &bflags);
+       res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);
        if (res == SCSI_SCAN_LUN_PRESENT) {
                if (bflags & BLIST_KEY) {
                        sdev->lockable = 0;
@@@ -1475,6 -1549,12 +1550,12 @@@ void scsi_scan_target(struct device *pa
  {
        struct Scsi_Host *shost = dev_to_shost(parent);
  
+       if (strncmp(scsi_scan_type, "none", 4) == 0)
+               return;
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
        mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost))
                __scsi_scan_target(parent, channel, id, lun, rescan);
@@@ -1520,6 -1600,9 +1601,9 @@@ int scsi_scan_host_selected(struct Scsi
                "%s: <%u:%u:%u>\n",
                __FUNCTION__, channel, id, lun));
  
+       if (!shost->async_scan)
+               scsi_complete_async_scans();
        if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
            ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
            ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
        return 0;
  }
  
+ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
+ {
+       struct scsi_device *sdev;
+       shost_for_each_device(sdev, shost) {
+               if (scsi_sysfs_add_sdev(sdev) != 0)
+                       scsi_destroy_sdev(sdev);
+       }
+ }
+ /**
+  * scsi_prep_async_scan - prepare for an async scan
+  * @shost: the host which will be scanned
+  * Returns: a cookie to be passed to scsi_finish_async_scan()
+  *
+  * Tells the midlayer this host is going to do an asynchronous scan.
+  * It reserves the host's position in the scanning list and ensures
+  * that other asynchronous scans started after this one won't affect the
+  * ordering of the discovered devices.
+  */
+ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
+ {
+       struct async_scan_data *data;
+       if (strncmp(scsi_scan_type, "sync", 4) == 0)
+               return NULL;
+       if (shost->async_scan) {
+               printk("%s called twice for host %d", __FUNCTION__,
+                               shost->host_no);
+               dump_stack();
+               return NULL;
+       }
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               goto err;
+       data->shost = scsi_host_get(shost);
+       if (!data->shost)
+               goto err;
+       init_completion(&data->prev_finished);
+       spin_lock(&async_scan_lock);
+       shost->async_scan = 1;
+       if (list_empty(&scanning_hosts))
+               complete(&data->prev_finished);
+       list_add_tail(&data->list, &scanning_hosts);
+       spin_unlock(&async_scan_lock);
+       return data;
+  err:
+       kfree(data);
+       return NULL;
+ }
+ /**
+  * scsi_finish_async_scan - asynchronous scan has finished
+  * @data: cookie returned from earlier call to scsi_prep_async_scan()
+  *
+  * All the devices currently attached to this host have been found.
+  * This function announces all the devices it has found to the rest
+  * of the system.
+  */
+ static void scsi_finish_async_scan(struct async_scan_data *data)
+ {
+       struct Scsi_Host *shost;
+       if (!data)
+               return;
+       shost = data->shost;
+       if (!shost->async_scan) {
+               printk("%s called twice for host %d", __FUNCTION__,
+                               shost->host_no);
+               dump_stack();
+               return;
+       }
+       wait_for_completion(&data->prev_finished);
+       scsi_sysfs_add_devices(shost);
+       spin_lock(&async_scan_lock);
+       shost->async_scan = 0;
+       list_del(&data->list);
+       if (!list_empty(&scanning_hosts)) {
+               struct async_scan_data *next = list_entry(scanning_hosts.next,
+                               struct async_scan_data, list);
+               complete(&next->prev_finished);
+       }
+       spin_unlock(&async_scan_lock);
+       scsi_host_put(shost);
+       kfree(data);
+ }
+ static void do_scsi_scan_host(struct Scsi_Host *shost)
+ {
+       if (shost->hostt->scan_finished) {
+               unsigned long start = jiffies;
+               if (shost->hostt->scan_start)
+                       shost->hostt->scan_start(shost);
+               while (!shost->hostt->scan_finished(shost, jiffies - start))
+                       msleep(10);
+       } else {
+               scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+                               SCAN_WILD_CARD, 0);
+       }
+ }
+ static int do_scan_async(void *_data)
+ {
+       struct async_scan_data *data = _data;
+       do_scsi_scan_host(data->shost);
+       scsi_finish_async_scan(data);
+       return 0;
+ }
  /**
   * scsi_scan_host - scan the given adapter
   * @shost:    adapter to scan
   **/
  void scsi_scan_host(struct Scsi_Host *shost)
  {
-       scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
-                               SCAN_WILD_CARD, 0);
+       struct async_scan_data *data;
+       if (strncmp(scsi_scan_type, "none", 4) == 0)
+               return;
+       data = scsi_prep_async_scan(shost);
+       if (!data) {
+               do_scsi_scan_host(shost);
+               return;
+       }
+       kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
  }
  EXPORT_SYMBOL(scsi_scan_host);
  
diff --combined include/scsi/libsas.h
@@@ -201,14 -201,9 +201,14 @@@ struct domain_device 
          void *lldd_dev;
  };
  
 +struct sas_discovery_event {
 +      struct work_struct work;
 +      struct asd_sas_port *port;
 +};
 +
  struct sas_discovery {
        spinlock_t disc_event_lock;
 -      struct work_struct disc_work[DISC_NUM_EVENTS];
 +      struct sas_discovery_event disc_work[DISC_NUM_EVENTS];
        unsigned long    pending;
        u8     fanout_sas_addr[8];
        u8     eeds_a[8];
@@@ -254,19 -249,14 +254,19 @@@ struct asd_sas_port 
        void *lldd_port;          /* not touched by the sas class code */
  };
  
 +struct asd_sas_event {
 +      struct work_struct work;
 +      struct asd_sas_phy *phy;
 +};
 +
  /* The phy pretty much is controlled by the LLDD.
   * The class only reads those fields.
   */
  struct asd_sas_phy {
  /* private: */
        /* protected by ha->event_lock */
 -      struct work_struct   port_events[PORT_NUM_EVENTS];
 -      struct work_struct   phy_events[PHY_NUM_EVENTS];
 +      struct asd_sas_event   port_events[PORT_NUM_EVENTS];
 +      struct asd_sas_event   phy_events[PHY_NUM_EVENTS];
  
        unsigned long port_events_pending;
        unsigned long phy_events_pending;
@@@ -318,15 -308,10 +318,15 @@@ struct scsi_core 
        int               queue_thread_kill;
  };
  
 +struct sas_ha_event {
 +      struct work_struct work;
 +      struct sas_ha_struct *ha;
 +};
 +
  struct sas_ha_struct {
  /* private: */
        spinlock_t       event_lock;
 -      struct work_struct ha_events[HA_NUM_EVENTS];
 +      struct sas_ha_event ha_events[HA_NUM_EVENTS];
        unsigned long    pending;
  
        struct scsi_core core;
        void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event);
  
        void *lldd_ha;            /* not touched by sas class code */
+       struct list_head eh_done_q;
  };
  
  #define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)
@@@ -542,13 -529,16 +544,16 @@@ struct sas_task 
  
        void   *lldd_task;        /* for use by LLDDs */
        void   *uldd_task;
+       struct work_struct abort_work;
  };
  
  
  
- #define SAS_TASK_STATE_PENDING  1
- #define SAS_TASK_STATE_DONE     2
- #define SAS_TASK_STATE_ABORTED  4
+ #define SAS_TASK_STATE_PENDING      1
+ #define SAS_TASK_STATE_DONE         2
+ #define SAS_TASK_STATE_ABORTED      4
+ #define SAS_TASK_INITIATOR_ABORTED  8
  
  static inline struct sas_task *sas_alloc_task(gfp_t flags)
  {
@@@ -608,6 -598,7 +613,7 @@@ struct sas_domain_function_template 
  extern int sas_register_ha(struct sas_ha_struct *);
  extern int sas_unregister_ha(struct sas_ha_struct *);
  
+ int sas_phy_reset(struct sas_phy *phy, int hard_reset);
  extern int sas_queuecommand(struct scsi_cmnd *,
                     void (*scsi_done)(struct scsi_cmnd *));
  extern int sas_target_alloc(struct scsi_target *);
@@@ -640,4 -631,6 +646,6 @@@ void sas_unregister_dev(struct domain_d
  
  void sas_init_dev(struct domain_device *);
  
+ void sas_task_abort(struct sas_task *task);
  #endif /* _SASLIB_H_ */