Commit f3187195 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

libata: separate out ata_host_alloc() and ata_host_register()

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: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent ecef7253
...@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, ...@@ -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 unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(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; static struct workqueue_struct *ata_wq;
struct workqueue_struct *ata_aux_wq; struct workqueue_struct *ata_aux_wq;
...@@ -5666,42 +5666,35 @@ void ata_dev_init(struct ata_device *dev) ...@@ -5666,42 +5666,35 @@ void ata_dev_init(struct ata_device *dev)
} }
/** /**
* ata_port_init - Initialize an ata_port structure * ata_port_alloc - allocate and initialize basic ATA port resources
* @ap: Structure to initialize * @host: ATA host this allocated port belongs to
* @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
* *
* Initialize a new ata_port structure. * Allocate and initialize basic ATA port resources.
*
* RETURNS:
* Allocate ATA port on success, NULL on failure.
* *
* LOCKING: * LOCKING:
* Inherited from caller. * Inherited from calling layer (may sleep).
*/ */
void ata_port_init(struct ata_port *ap, struct ata_host *host, struct ata_port *ata_port_alloc(struct ata_host *host)
const struct ata_probe_ent *ent, unsigned int port_no)
{ {
struct ata_port *ap;
unsigned int i; unsigned int i;
DPRINTK("ENTER\n");
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (!ap)
return NULL;
ap->lock = &host->lock; ap->lock = &host->lock;
ap->flags = ATA_FLAG_DISABLED; ap->flags = ATA_FLAG_DISABLED;
ap->print_id = ata_print_id++; ap->print_id = -1;
ap->ctl = ATA_DEVCTL_OBS; ap->ctl = ATA_DEVCTL_OBS;
ap->host = host; ap->host = host;
ap->dev = ent->dev; ap->dev = host->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->hw_sata_spd_limit = UINT_MAX; ap->hw_sata_spd_limit = UINT_MAX;
ap->active_tag = ATA_TAG_POISON; ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF; ap->last_ctl = 0xFF;
...@@ -5721,10 +5714,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ...@@ -5721,10 +5714,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
INIT_LIST_HEAD(&ap->eh_done_q); INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q); init_waitqueue_head(&ap->eh_wait_q);
/* set cable type */
ap->cbl = ATA_CBL_NONE; ap->cbl = ATA_CBL_NONE;
if (ap->flags & ATA_FLAG_SATA)
ap->cbl = ATA_CBL_SATA;
for (i = 0; i < ATA_MAX_DEVICES; i++) { for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i]; struct ata_device *dev = &ap->device[i];
...@@ -5737,77 +5727,6 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ...@@ -5737,77 +5727,6 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
ap->stats.unhandled_irq = 1; ap->stats.unhandled_irq = 1;
ap->stats.idle_irq = 1; ap->stats.idle_irq = 1;
#endif #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; return ap;
} }
...@@ -5845,6 +5764,71 @@ static void ata_host_release(struct device *gendev, void *res) ...@@ -5845,6 +5764,71 @@ static void ata_host_release(struct device *gendev, void *res)
dev_set_drvdata(gendev, NULL); dev_set_drvdata(gendev, NULL);
} }
/**
* 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 * ata_host_start - start and freeze ports of an ATA host
* @host: ATA host to start ports for * @host: ATA host to start ports for
...@@ -5852,7 +5836,8 @@ static void ata_host_release(struct device *gendev, void *res) ...@@ -5852,7 +5836,8 @@ static void ata_host_release(struct device *gendev, void *res)
* Start and then freeze ports of @host. Started status is * Start and then freeze ports of @host. Started status is
* recorded in host->flags, so this function can be called * recorded in host->flags, so this function can be called
* multiple times. Ports are guaranteed to get started only * 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: * LOCKING:
* Inherited from calling layer (may sleep). * Inherited from calling layer (may sleep).
...@@ -5870,6 +5855,9 @@ int ata_host_start(struct ata_host *host) ...@@ -5870,6 +5855,9 @@ int ata_host_start(struct ata_host *host)
for (i = 0; i < host->n_ports; i++) { for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->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) { if (ap->ops->port_start) {
rc = ap->ops->port_start(ap); rc = ap->ops->port_start(ap);
if (rc) { if (rc) {
...@@ -5906,7 +5894,7 @@ int ata_host_start(struct ata_host *host) ...@@ -5906,7 +5894,7 @@ int ata_host_start(struct ata_host *host)
* PCI/etc. bus probe sem. * PCI/etc. bus probe sem.
* *
*/ */
/* KILLME - the only user left is ipr */
void ata_host_init(struct ata_host *host, struct device *dev, void ata_host_init(struct ata_host *host, struct device *dev,
unsigned long flags, const struct ata_port_operations *ops) unsigned long flags, const struct ata_port_operations *ops)
{ {
...@@ -5916,6 +5904,143 @@ void ata_host_init(struct ata_host *host, struct device *dev, ...@@ -5916,6 +5904,143 @@ void ata_host_init(struct ata_host *host, struct device *dev,
host->ops = ops; host->ops = ops;
} }
/**
* 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 * ata_device_add - Register hardware device with ATA and SCSI layers
* @ent: Probe information describing hardware device to be registered * @ent: Probe information describing hardware device to be registered
...@@ -5948,62 +6073,53 @@ int ata_device_add(const struct ata_probe_ent *ent) ...@@ -5948,62 +6073,53 @@ int ata_device_add(const struct ata_probe_ent *ent)
return 0; 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)) if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
return 0; return 0;
/* alloc a container for our list of ATA ports (buses) */ /* allocate host */
host = devres_alloc(ata_host_release, sizeof(struct ata_host) + host = ata_host_alloc(dev, ent->n_ports);
(ent->n_ports * sizeof(void *)), GFP_KERNEL);
if (!host)
goto err_out;
devres_add(dev, host);
dev_set_drvdata(dev, host);
ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
host->n_ports = ent->n_ports;
host->irq = ent->irq; host->irq = ent->irq;
host->irq2 = ent->irq2; host->irq2 = ent->irq2;
host->iomap = ent->iomap; host->iomap = ent->iomap;
host->private_data = ent->private_data; 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++) { for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap; struct ata_port *ap = host->ports[i];
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;
/* dummy? */ /* dummy? */
if (ent->dummy_port_mask & (1 << i)) { if (ent->dummy_port_mask & (1 << i)) {
ata_port_printk(ap, KERN_INFO, "DUMMY\n");
ap->ops = &ata_dummy_port_ops; ap->ops = &ata_dummy_port_ops;
continue; continue;
} }
/* Report the secondary IRQ for second channel legacy */ if (ap->port_no == 1 && ent->pinfo2) {
if (i == 1 && ent->irq2) ap->pio_mask = ent->pinfo2->pio_mask;
irq_line = ent->irq2; ap->mwdma_mask = ent->pinfo2->mwdma_mask;
ap->udma_mask = ent->pinfo2->udma_mask;
xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | ap->flags |= ent->pinfo2->flags;
(ap->mwdma_mask << ATA_SHIFT_MWDMA) | ap->ops = ent->pinfo2->port_ops;
(ap->pio_mask << ATA_SHIFT_PIO); } 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 */ memcpy(&ap->ioaddr, &ent->port[ap->port_no],
ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " sizeof(struct ata_ioports));
"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);
} }
/* start ports */ /* start and freeze ports before requesting IRQ */
rc = ata_host_start(host); rc = ata_host_start(host);
if (rc) if (rc)
goto err_out; goto err_out;
...@@ -6036,80 +6152,17 @@ int ata_device_add(const struct ata_probe_ent *ent) ...@@ -6036,80 +6152,17 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* resource acquisition complete */ /* resource acquisition complete */
devres_remove_group(dev, ata_device_add); devres_remove_group(dev, ata_device_add);
/* perform each probe synchronously */ /* register */
DPRINTK("probe begin\n"); rc = ata_host_register(host, ent->sht);
for (i = 0; i < host->n_ports; i++) { if (rc)
struct ata_port *ap = host->ports[i]; goto err_out;
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);
}
VPRINTK("EXIT, returning %u\n", ent->n_ports); VPRINTK("EXIT, returning %u\n", host->n_ports);
return ent->n_ports; /* success */ return host->n_ports; /* success */
err_out: err_out:
devres_release_group(dev, ata_device_add); devres_release_group(dev, ata_device_add);
VPRINTK("EXIT, returning %d\n", rc); VPRINTK("EXIT, returning 0\n");
return 0; return 0;
} }
...@@ -6493,7 +6546,9 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_ops); ...@@ -6493,7 +6546,9 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_host_alloc);
EXPORT_SYMBOL_GPL(ata_host_start); EXPORT_SYMBOL_GPL(ata_host_start);
EXPORT_SYMBOL_GPL(ata_host_register);
EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_device_add);
EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_host_detach);
EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init);
......
...@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { ...@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
* libata transport template. libata doesn't do real transport stuff. * libata transport template. libata doesn't do real transport stuff.
* It just needs the eh_timed_out hook. * 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_strategy_handler = ata_scsi_error,
.eh_timed_out = ata_scsi_timed_out, .eh_timed_out = ata_scsi_timed_out,
.user_scan = ata_scsi_user_scan, .user_scan = ata_scsi_user_scan,
...@@ -2961,6 +2961,48 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ...@@ -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) void ata_scsi_scan_host(struct ata_port *ap)
{ {
unsigned int i; unsigned int i;
...@@ -3237,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host, ...@@ -3237,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
struct ata_port_info *port_info, struct ata_port_info *port_info,
struct Scsi_Host *shost) struct Scsi_Host *shost)
{ {
struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL); struct ata_port *ap;
struct ata_probe_ent *ent;
ap = ata_port_alloc(host);
if (!ap) if (!ap)
return NULL; return NULL;
ent = ata_probe_ent_alloc(host->dev, port_info); ap->port_no = 0;
if (!ent) {
kfree(ap);
return NULL;
}
ata_port_init(ap, host, ent, 0);
ap->lock = shost->host_lock; 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; return ap;
} }
EXPORT_SYMBOL_GPL(ata_sas_port_alloc); EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
...@@ -3307,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *ap) ...@@ -3307,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *ap)
{ {
int rc = ap->ops->port_start(ap); int rc = ap->ops->port_start(ap);
if (!rc) if (!rc) {
ap->print_id = ata_print_id++;
rc = ata_bus_probe(ap); rc = ata_bus_probe(ap);
}
return rc; return rc;
} }
......
...@@ -52,6 +52,7 @@ enum { ...@@ -52,6 +52,7 @@ enum {
ATA_DNXFER_QUIET = (1 << 31), ATA_DNXFER_QUIET = (1 << 31),
}; };
extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq; extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled; extern int atapi_enabled;
extern int atapi_dmadir; extern int atapi_dmadir;
...@@ -92,10 +93,9 @@ extern int ata_flush_cache(struct ata_device *dev); ...@@ -92,10 +93,9 @@ extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(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_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_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, extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
const struct ata_port_info *port); const struct ata_port_info *port);
extern struct ata_port *ata_port_alloc(struct ata_host *host);
/* libata-acpi.c */ /* libata-acpi.c */
#ifdef CONFIG_SATA_ACPI #ifdef CONFIG_SATA_ACPI
...@@ -113,8 +113,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) ...@@ -113,8 +113,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
#endif #endif
/* libata-scsi.c */ /* 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 void ata_scsi_scan_host(struct ata_port *ap);
extern int ata_scsi_offline_dev(struct ata_device *dev); extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work); extern void ata_scsi_hotplug(struct work_struct *work);
......
...@@ -733,7 +733,10 @@ extern int ata_pci_device_resume(struct pci_dev *pdev); ...@@ -733,7 +733,10 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
#endif #endif
extern int ata_pci_clear_simplex(struct pci_dev *pdev); extern int ata_pci_clear_simplex(struct pci_dev *pdev);
#endif /* CONFIG_PCI */ #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_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 int ata_device_add(const struct ata_probe_ent *ent);
extern void ata_host_detach(struct ata_host *host); extern void ata_host_detach(struct ata_host *host);
extern void ata_host_init(struct ata_host *, struct device *, extern void ata_host_init(struct ata_host *, struct device *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment