libata: separate out ata_host_alloc() and ata_host_register()
authorTejun Heo <htejun@gmail.com>
Tue, 17 Apr 2007 14:44:07 +0000 (23:44 +0900)
committerJeff Garzik <jeff@garzik.org>
Sat, 28 Apr 2007 18:16:03 +0000 (14:16 -0400)
Reorganize ata_host_alloc() and its subroutines into the following
three functions.

* ata_host_alloc() : allocates host and its ports.  shost is not
  registered automatically.

* ata_scsi_add_hosts() : allocates and adds shosts associated with an
  ATA host.  Used by ata_host_register().

* ata_host_register() : takes a fully initialized ata_host structure
  and registers it to libata layer and probes it.

Only ata_host_alloc() and ata_host_register() are exported.
ata_device_add() is rewritten using the above functions.  This patch
does not introduce any observable behavior change.  Things worth
mentioning.

* print_id is assigned at registration time and LLDs are allowed to
  overallocate ports and reduce host->n_ports during initialization.
  ata_host_register() will throw away unused ports automatically.

* All SCSI host initialization stuff now resides in
  ata_scsi_add_hosts() in libata-scsi.c, where it should be.

* ipr is now the only user of ata_host_init().  Either kill it by
  converting ipr to use ata_host_alloc() and friends or rename and
  move it to libata-scsi.c

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/libata.h
include/linux/libata.h

index aea766a..b23f35a 100644 (file)
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
 static void ata_dev_xfermask(struct ata_device *dev);
 
-static unsigned int ata_print_id = 1;
+unsigned int ata_print_id = 1;
 static struct workqueue_struct *ata_wq;
 
 struct workqueue_struct *ata_aux_wq;
@@ -5666,42 +5666,35 @@ void ata_dev_init(struct ata_device *dev)
 }
 
 /**
- *     ata_port_init - Initialize an ata_port structure
- *     @ap: Structure to initialize
- *     @host: Collection of hosts to which @ap belongs
- *     @ent: Probe information provided by low-level driver
- *     @port_no: Port number associated with this ata_port
+ *     ata_port_alloc - allocate and initialize basic ATA port resources
+ *     @host: ATA host this allocated port belongs to
  *
- *     Initialize a new ata_port structure.
+ *     Allocate and initialize basic ATA port resources.
+ *
+ *     RETURNS:
+ *     Allocate ATA port on success, NULL on failure.
  *
  *     LOCKING:
- *     Inherited from caller.
+ *     Inherited from calling layer (may sleep).
  */
-void ata_port_init(struct ata_port *ap, struct ata_host *host,
-                  const struct ata_probe_ent *ent, unsigned int port_no)
+struct ata_port *ata_port_alloc(struct ata_host *host)
 {
+       struct ata_port *ap;
        unsigned int i;
 
+       DPRINTK("ENTER\n");
+
+       ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+       if (!ap)
+               return NULL;
+
        ap->lock = &host->lock;
        ap->flags = ATA_FLAG_DISABLED;
-       ap->print_id = ata_print_id++;
+       ap->print_id = -1;
        ap->ctl = ATA_DEVCTL_OBS;
        ap->host = host;
-       ap->dev = ent->dev;
-       ap->port_no = port_no;
-       if (port_no == 1 && ent->pinfo2) {
-               ap->pio_mask = ent->pinfo2->pio_mask;
-               ap->mwdma_mask = ent->pinfo2->mwdma_mask;
-               ap->udma_mask = ent->pinfo2->udma_mask;
-               ap->flags |= ent->pinfo2->flags;
-               ap->ops = ent->pinfo2->port_ops;
-       } else {
-               ap->pio_mask = ent->pio_mask;
-               ap->mwdma_mask = ent->mwdma_mask;
-               ap->udma_mask = ent->udma_mask;
-               ap->flags |= ent->port_flags;
-               ap->ops = ent->port_ops;
-       }
+       ap->dev = host->dev;
+
        ap->hw_sata_spd_limit = UINT_MAX;
        ap->active_tag = ATA_TAG_POISON;
        ap->last_ctl = 0xFF;
@@ -5721,10 +5714,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
 
-       /* set cable type */
        ap->cbl = ATA_CBL_NONE;
-       if (ap->flags & ATA_FLAG_SATA)
-               ap->cbl = ATA_CBL_SATA;
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
@@ -5737,77 +5727,6 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
        ap->stats.unhandled_irq = 1;
        ap->stats.idle_irq = 1;
 #endif
-
-       memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
-}
-
-/**
- *     ata_port_init_shost - Initialize SCSI host associated with ATA port
- *     @ap: ATA port to initialize SCSI host for
- *     @shost: SCSI host associated with @ap
- *
- *     Initialize SCSI host @shost associated with ATA port @ap.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
-{
-       ap->scsi_host = shost;
-
-       shost->unique_id = ap->print_id;
-       shost->max_id = 16;
-       shost->max_lun = 1;
-       shost->max_channel = 1;
-       shost->max_cmd_len = 16;
-}
-
-/**
- *     ata_port_add - Attach low-level ATA driver to system
- *     @ent: Information provided by low-level driver
- *     @host: Collections of ports to which we add
- *     @port_no: Port number associated with this host
- *
- *     Attach low-level ATA driver to system.
- *
- *     LOCKING:
- *     PCI/etc. bus probe sem.
- *
- *     RETURNS:
- *     New ata_port on success, for NULL on error.
- */
-static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
-                                     struct ata_host *host,
-                                     unsigned int port_no)
-{
-       struct Scsi_Host *shost;
-       struct ata_port *ap;
-
-       DPRINTK("ENTER\n");
-
-       if (!ent->port_ops->error_handler &&
-           !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
-               printk(KERN_ERR "ata%u: no reset mechanism available\n",
-                      port_no);
-               return NULL;
-       }
-
-       ap = kzalloc(sizeof(struct ata_port), GFP_KERNEL);
-       if (!ap)
-               return NULL;
-
-       shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port *));
-       if (!shost) {
-               kfree(ap);
-               return NULL;
-       }
-
-       *(struct ata_port **)&shost->hostdata[0] = ap;
-       shost->transportt = &ata_scsi_transport_template;
-
-       ata_port_init(ap, host, ent, port_no);
-       ata_port_init_shost(ap, shost);
-
        return ap;
 }
 
@@ -5846,13 +5765,79 @@ static void ata_host_release(struct device *gendev, void *res)
 }
 
 /**
+ *     ata_host_alloc - allocate and init basic ATA host resources
+ *     @dev: generic device this host is associated with
+ *     @max_ports: maximum number of ATA ports associated with this host
+ *
+ *     Allocate and initialize basic ATA host resources.  LLD calls
+ *     this function to allocate a host, initializes it fully and
+ *     attaches it using ata_host_register().
+ *
+ *     @max_ports ports are allocated and host->n_ports is
+ *     initialized to @max_ports.  The caller is allowed to decrease
+ *     host->n_ports before calling ata_host_register().  The unused
+ *     ports will be automatically freed on registration.
+ *
+ *     RETURNS:
+ *     Allocate ATA host on success, NULL on failure.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ */
+struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
+{
+       struct ata_host *host;
+       size_t sz;
+       int i;
+
+       DPRINTK("ENTER\n");
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return NULL;
+
+       /* alloc a container for our list of ATA ports (buses) */
+       sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
+       /* alloc a container for our list of ATA ports (buses) */
+       host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+       if (!host)
+               goto err_out;
+
+       devres_add(dev, host);
+       dev_set_drvdata(dev, host);
+
+       spin_lock_init(&host->lock);
+       host->dev = dev;
+       host->n_ports = max_ports;
+
+       /* allocate ports bound to this host */
+       for (i = 0; i < max_ports; i++) {
+               struct ata_port *ap;
+
+               ap = ata_port_alloc(host);
+               if (!ap)
+                       goto err_out;
+
+               ap->port_no = i;
+               host->ports[i] = ap;
+       }
+
+       devres_remove_group(dev, NULL);
+       return host;
+
+ err_out:
+       devres_release_group(dev, NULL);
+       return NULL;
+}
+
+/**
  *     ata_host_start - start and freeze ports of an ATA host
  *     @host: ATA host to start ports for
  *
  *     Start and then freeze ports of @host.  Started status is
  *     recorded in host->flags, so this function can be called
  *     multiple times.  Ports are guaranteed to get started only
- *     once.
+ *     once.  If host->ops isn't initialized yet, its set to the
+ *     first non-dummy port ops.
  *
  *     LOCKING:
  *     Inherited from calling layer (may sleep).
@@ -5870,6 +5855,9 @@ int ata_host_start(struct ata_host *host)
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
+               if (!host->ops && !ata_port_is_dummy(ap))
+                       host->ops = ap->ops;
+
                if (ap->ops->port_start) {
                        rc = ap->ops->port_start(ap);
                        if (rc) {
@@ -5906,7 +5894,7 @@ int ata_host_start(struct ata_host *host)
  *     PCI/etc. bus probe sem.
  *
  */
-
+/* KILLME - the only user left is ipr */
 void ata_host_init(struct ata_host *host, struct device *dev,
                   unsigned long flags, const struct ata_port_operations *ops)
 {
@@ -5917,6 +5905,143 @@ void ata_host_init(struct ata_host *host, struct device *dev,
 }
 
 /**
+ *     ata_host_register - register initialized ATA host
+ *     @host: ATA host to register
+ *     @sht: template for SCSI host
+ *
+ *     Register initialized ATA host.  @host is allocated using
+ *     ata_host_alloc() and fully initialized by LLD.  This function
+ *     starts ports, registers @host with ATA and SCSI layers and
+ *     probe registered devices.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
+{
+       int i, rc;
+
+       /* host must have been started */
+       if (!(host->flags & ATA_HOST_STARTED)) {
+               dev_printk(KERN_ERR, host->dev,
+                          "BUG: trying to register unstarted host\n");
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       /* Blow away unused ports.  This happens when LLD can't
+        * determine the exact number of ports to allocate at
+        * allocation time.
+        */
+       for (i = host->n_ports; host->ports[i]; i++)
+               kfree(host->ports[i]);
+
+       /* give ports names and add SCSI hosts */
+       for (i = 0; i < host->n_ports; i++)
+               host->ports[i]->print_id = ata_print_id++;
+
+       rc = ata_scsi_add_hosts(host, sht);
+       if (rc)
+               return rc;
+
+       /* set cable, sata_spd_limit and report */
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               int irq_line;
+               u32 scontrol;
+               unsigned long xfer_mask;
+
+               /* set SATA cable type if still unset */
+               if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA))
+                       ap->cbl = ATA_CBL_SATA;
+
+               /* init sata_spd_limit to the current value */
+               if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+                       int spd = (scontrol >> 4) & 0xf;
+                       ap->hw_sata_spd_limit &= (1 << spd) - 1;
+               }
+               ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
+               /* report the secondary IRQ for second channel legacy */
+               irq_line = host->irq;
+               if (i == 1 && host->irq2)
+                       irq_line = host->irq2;
+
+               xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+                                             ap->udma_mask);
+
+               /* print per-port info to dmesg */
+               if (!ata_port_is_dummy(ap))
+                       ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+                                       "ctl 0x%p bmdma 0x%p irq %d\n",
+                                       ap->cbl == ATA_CBL_SATA ? 'S' : 'P',
+                                       ata_mode_string(xfer_mask),
+                                       ap->ioaddr.cmd_addr,
+                                       ap->ioaddr.ctl_addr,
+                                       ap->ioaddr.bmdma_addr,
+                                       irq_line);
+               else
+                       ata_port_printk(ap, KERN_INFO, "DUMMY\n");
+       }
+
+       /* perform each probe synchronously */
+       DPRINTK("probe begin\n");
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               int rc;
+
+               /* probe */
+               if (ap->ops->error_handler) {
+                       struct ata_eh_info *ehi = &ap->eh_info;
+                       unsigned long flags;
+
+                       ata_port_probe(ap);
+
+                       /* kick EH for boot probing */
+                       spin_lock_irqsave(ap->lock, flags);
+
+                       ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+                       ehi->action |= ATA_EH_SOFTRESET;
+                       ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+                       ap->pflags |= ATA_PFLAG_LOADING;
+                       ata_port_schedule_eh(ap);
+
+                       spin_unlock_irqrestore(ap->lock, flags);
+
+                       /* wait for EH to finish */
+                       ata_port_wait_eh(ap);
+               } else {
+                       DPRINTK("ata%u: bus probe begin\n", ap->print_id);
+                       rc = ata_bus_probe(ap);
+                       DPRINTK("ata%u: bus probe end\n", ap->print_id);
+
+                       if (rc) {
+                               /* FIXME: do something useful here?
+                                * Current libata behavior will
+                                * tear down everything when
+                                * the module is removed
+                                * or the h/w is unplugged.
+                                */
+                       }
+               }
+       }
+
+       /* probes are done, now scan each port's disk(s) */
+       DPRINTK("host probe begin\n");
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               ata_scsi_scan_host(ap);
+       }
+
+       return 0;
+}
+
+/**
  *     ata_device_add - Register hardware device with ATA and SCSI layers
  *     @ent: Probe information describing hardware device to be registered
  *
@@ -5948,62 +6073,53 @@ int ata_device_add(const struct ata_probe_ent *ent)
                return 0;
        }
 
+       if (!ent->port_ops->error_handler &&
+           !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
+               dev_printk(KERN_ERR, dev, "no reset mechanism available\n");
+               return 0;
+       }
+
        if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
                return 0;
 
-       /* alloc a container for our list of ATA ports (buses) */
-       host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
-                           (ent->n_ports * sizeof(void *)), GFP_KERNEL);
-       if (!host)
-               goto err_out;
-       devres_add(dev, host);
-       dev_set_drvdata(dev, host);
+       /* allocate host */
+       host = ata_host_alloc(dev, ent->n_ports);
 
-       ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
-       host->n_ports = ent->n_ports;
        host->irq = ent->irq;
        host->irq2 = ent->irq2;
        host->iomap = ent->iomap;
        host->private_data = ent->private_data;
+       host->ops = ent->port_ops;
+       host->flags = ent->_host_flags;
 
-       /* register each port bound to this device */
        for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap;
-               unsigned long xfer_mode_mask;
-               int irq_line = ent->irq;
-
-               ap = ata_port_add(ent, host, i);
-               host->ports[i] = ap;
-               if (!ap)
-                       goto err_out;
+               struct ata_port *ap = host->ports[i];
 
                /* dummy? */
                if (ent->dummy_port_mask & (1 << i)) {
-                       ata_port_printk(ap, KERN_INFO, "DUMMY\n");
                        ap->ops = &ata_dummy_port_ops;
                        continue;
                }
 
-               /* Report the secondary IRQ for second channel legacy */
-               if (i == 1 && ent->irq2)
-                       irq_line = ent->irq2;
-
-               xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
-                               (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
-                               (ap->pio_mask << ATA_SHIFT_PIO);
+               if (ap->port_no == 1 && ent->pinfo2) {
+                       ap->pio_mask = ent->pinfo2->pio_mask;
+                       ap->mwdma_mask = ent->pinfo2->mwdma_mask;
+                       ap->udma_mask = ent->pinfo2->udma_mask;
+                       ap->flags |= ent->pinfo2->flags;
+                       ap->ops = ent->pinfo2->port_ops;
+               } else {
+                       ap->pio_mask = ent->pio_mask;
+                       ap->mwdma_mask = ent->mwdma_mask;
+                       ap->udma_mask = ent->udma_mask;
+                       ap->flags |= ent->port_flags;
+                       ap->ops = ent->port_ops;
+               }
 
-               /* print per-port info to dmesg */
-               ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
-                               "ctl 0x%p bmdma 0x%p irq %d\n",
-                               ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
-                               ata_mode_string(xfer_mode_mask),
-                               ap->ioaddr.cmd_addr,
-                               ap->ioaddr.ctl_addr,
-                               ap->ioaddr.bmdma_addr,
-                               irq_line);
+               memcpy(&ap->ioaddr, &ent->port[ap->port_no],
+                      sizeof(struct ata_ioports));
        }
 
-       /* start ports */
+       /* start and freeze ports before requesting IRQ */
        rc = ata_host_start(host);
        if (rc)
                goto err_out;
@@ -6036,80 +6152,17 @@ int ata_device_add(const struct ata_probe_ent *ent)
        /* resource acquisition complete */
        devres_remove_group(dev, ata_device_add);
 
-       /* perform each probe synchronously */
-       DPRINTK("probe begin\n");
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-               u32 scontrol;
-               int rc;
-
-               /* init sata_spd_limit to the current value */
-               if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
-                       int spd = (scontrol >> 4) & 0xf;
-                       ap->hw_sata_spd_limit &= (1 << spd) - 1;
-               }
-               ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
-               rc = scsi_add_host(ap->scsi_host, dev);
-               if (rc) {
-                       ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
-                       /* FIXME: do something useful here */
-                       /* FIXME: handle unconditional calls to
-                        * scsi_scan_host and ata_host_remove, below,
-                        * at the very least
-                        */
-               }
-
-               if (ap->ops->error_handler) {
-                       struct ata_eh_info *ehi = &ap->eh_info;
-                       unsigned long flags;
-
-                       ata_port_probe(ap);
-
-                       /* kick EH for boot probing */
-                       spin_lock_irqsave(ap->lock, flags);
-
-                       ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
-                       ehi->action |= ATA_EH_SOFTRESET;
-                       ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
-
-                       ap->pflags |= ATA_PFLAG_LOADING;
-                       ata_port_schedule_eh(ap);
-
-                       spin_unlock_irqrestore(ap->lock, flags);
-
-                       /* wait for EH to finish */
-                       ata_port_wait_eh(ap);
-               } else {
-                       DPRINTK("ata%u: bus probe begin\n", ap->print_id);
-                       rc = ata_bus_probe(ap);
-                       DPRINTK("ata%u: bus probe end\n", ap->print_id);
-
-                       if (rc) {
-                               /* FIXME: do something useful here?
-                                * Current libata behavior will
-                                * tear down everything when
-                                * the module is removed
-                                * or the h/w is unplugged.
-                                */
-                       }
-               }
-       }
-
-       /* probes are done, now scan each port's disk(s) */
-       DPRINTK("host probe begin\n");
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-
-               ata_scsi_scan_host(ap);
-       }
+       /* register */
+       rc = ata_host_register(host, ent->sht);
+       if (rc)
+               goto err_out;
 
-       VPRINTK("EXIT, returning %u\n", ent->n_ports);
-       return ent->n_ports; /* success */
+       VPRINTK("EXIT, returning %u\n", host->n_ports);
+       return host->n_ports; /* success */
 
  err_out:
        devres_release_group(dev, ata_device_add);
-       VPRINTK("EXIT, returning %d\n", rc);
+       VPRINTK("EXIT, returning 0\n");
        return 0;
 }
 
@@ -6493,7 +6546,9 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_host_init);
+EXPORT_SYMBOL_GPL(ata_host_alloc);
 EXPORT_SYMBOL_GPL(ata_host_start);
+EXPORT_SYMBOL_GPL(ata_host_register);
 EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
index 563ef0b..9afba2b 100644 (file)
@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
  * libata transport template.  libata doesn't do real transport stuff.
  * It just needs the eh_timed_out hook.
  */
-struct scsi_transport_template ata_scsi_transport_template = {
+static struct scsi_transport_template ata_scsi_transport_template = {
        .eh_strategy_handler    = ata_scsi_error,
        .eh_timed_out           = ata_scsi_timed_out,
        .user_scan              = ata_scsi_user_scan,
@@ -2961,6 +2961,48 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
        }
 }
 
+int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
+{
+       int i, rc;
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               struct Scsi_Host *shost;
+
+               rc = -ENOMEM;
+               shost = scsi_host_alloc(sht, sizeof(struct ata_port *));
+               if (!shost)
+                       goto err_alloc;
+
+               *(struct ata_port **)&shost->hostdata[0] = ap;
+               ap->scsi_host = shost;
+
+               shost->transportt = &ata_scsi_transport_template;
+               shost->unique_id = ap->print_id;
+               shost->max_id = 16;
+               shost->max_lun = 1;
+               shost->max_channel = 1;
+               shost->max_cmd_len = 16;
+
+               rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+               if (rc)
+                       goto err_add;
+       }
+
+       return 0;
+
+ err_add:
+       scsi_host_put(host->ports[i]->scsi_host);
+ err_alloc:
+       while (--i >= 0) {
+               struct Scsi_Host *shost = host->ports[i]->scsi_host;
+
+               scsi_remove_host(shost);
+               scsi_host_put(shost);
+       }
+       return rc;
+}
+
 void ata_scsi_scan_host(struct ata_port *ap)
 {
        unsigned int i;
@@ -3237,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
                                    struct ata_port_info *port_info,
                                    struct Scsi_Host *shost)
 {
-       struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
-       struct ata_probe_ent *ent;
+       struct ata_port *ap;
 
+       ap = ata_port_alloc(host);
        if (!ap)
                return NULL;
 
-       ent = ata_probe_ent_alloc(host->dev, port_info);
-       if (!ent) {
-               kfree(ap);
-               return NULL;
-       }
-
-       ata_port_init(ap, host, ent, 0);
+       ap->port_no = 0;
        ap->lock = shost->host_lock;
-       devm_kfree(host->dev, ent);
+       ap->pio_mask = port_info->pio_mask;
+       ap->mwdma_mask = port_info->mwdma_mask;
+       ap->udma_mask = port_info->udma_mask;
+       ap->flags |= port_info->flags;
+       ap->ops = port_info->port_ops;
+       ap->cbl = ATA_CBL_SATA;
+
        return ap;
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
@@ -3307,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *ap)
 {
        int rc = ap->ops->port_start(ap);
 
-       if (!rc)
+       if (!rc) {
+               ap->print_id = ata_print_id++;
                rc = ata_bus_probe(ap);
+       }
 
        return rc;
 }
index 1f1e3a5..b4d5253 100644 (file)
@@ -52,6 +52,7 @@ enum {
        ATA_DNXFER_QUIET        = (1 << 31),
 };
 
+extern unsigned int ata_print_id;
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
@@ -92,10 +93,9 @@ extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
-                         const struct ata_probe_ent *ent, unsigned int port_no);
 extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
                                                 const struct ata_port_info *port);
+extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_SATA_ACPI
@@ -113,8 +113,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
 #endif
 
 /* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
+extern int ata_scsi_add_hosts(struct ata_host *host,
+                             struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
index bda26e8..06cf23f 100644 (file)
@@ -733,7 +733,10 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
 #endif
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
 #endif /* CONFIG_PCI */
+extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
 extern int ata_host_start(struct ata_host *host);
+extern int ata_host_register(struct ata_host *host,
+                            struct scsi_host_template *sht);
 extern int ata_device_add(const struct ata_probe_ent *ent);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,