Currently, libata creates a Scsi_Host per port. This was originally done to leverage SCSI's infrastructure to arbitrate among master/slave devices, but is not needed for most modern SATA controllers. And I _think_ it is not needed for master/slave if done properly, either. The patch below converts libata such that there is now a 1:1 correspondence between struct Scsi_Host and struct ata_host. ATA ports are represented as SCSI layer 'channels', which is more natural. This patch is an experiment, and not meant for upstream anytime soon. I just wanted to see what kind of effort would be required to get it to work. I was able to successfully boot the following patch on AHCI/x86-64/Fedora. It may work with other controllers -- TRY AT YOUR OWN RISK. It will probably fail for master/slave configurations, and SAS & PMP also need looking at. It yielded this lsscsi output on my AHCI box: [0:0:0:0] disk ATA ST3500320AS SD15 /dev/sda [0:2:0:0] disk ATA G.SKILL 128GB SS 02.1 /dev/sdb [0:5:0:0] cd/dvd PIONEER BD-ROM BDC-202 1.04 /dev/sr0 NOT-signed-off-by: me drivers/ata/ahci.c | 4 drivers/ata/libata-core.c | 17 +-- drivers/ata/libata-eh.c | 47 ++++++-- drivers/ata/libata-scsi.c | 237 +++++++++++++++++++++--------------------- drivers/ata/libata.h | 3 drivers/scsi/libsas/sas_ata.c | 2 include/linux/libata.h | 9 - 7 files changed, 184 insertions(+), 135 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 08186ec..b0468a8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -326,14 +326,18 @@ static ssize_t ahci_activity_store(struct ata_device *dev, static void ahci_init_sw_activity(struct ata_link *link); static struct device_attribute *ahci_shost_attrs[] = { +#if 0 &dev_attr_link_power_management_policy, &dev_attr_em_message_type, &dev_attr_em_message, +#endif NULL }; static struct device_attribute *ahci_sdev_attrs[] = { +#if 0 &dev_attr_sw_activity, +#endif &dev_attr_unload_heads, NULL }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 17c5d48..71f32dc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -95,6 +95,7 @@ static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); unsigned int ata_print_id = 1; +unsigned int ata_host_print_id = 1; static struct workqueue_struct *ata_wq; struct workqueue_struct *ata_aux_wq; @@ -2308,7 +2309,7 @@ static void ata_dev_config_ncq(struct ata_device *dev, return; } if (ap->flags & ATA_FLAG_NCQ) { - hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); + hdepth = min(ap->host->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; } @@ -5635,15 +5636,15 @@ static void ata_host_release(struct device *gendev, void *res) if (!ap) continue; - if (ap->scsi_host) - scsi_host_put(ap->scsi_host); - kfree(ap->pmp_link); kfree(ap->slave_link); kfree(ap); host->ports[i] = NULL; } + if (host->scsi_host) + scsi_host_put(host->scsi_host); + dev_set_drvdata(gendev, NULL); } @@ -6089,6 +6090,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = 0; i < host->n_ports; i++) host->ports[i]->print_id = ata_print_id++; + host->print_id = ata_host_print_id++; + rc = ata_scsi_add_hosts(host, sht); if (rc) return rc; @@ -6222,8 +6225,7 @@ static void ata_port_detach(struct ata_port *ap) cancel_rearming_delayed_work(&ap->hotplug_task); skip_eh: - /* remove the associated SCSI host */ - scsi_remove_host(ap->scsi_host); + return; } /** @@ -6242,6 +6244,9 @@ void ata_host_detach(struct ata_host *host) for (i = 0; i < host->n_ports; i++) ata_port_detach(host->ports[i]); + /* remove the associated SCSI host */ + scsi_remove_host(host->scsi_host); + /* the host is dead now, dissociate ACPI */ ata_acpi_dissociate(host); } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0183131..db8a66f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -466,14 +466,22 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, */ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) { - struct Scsi_Host *host = cmd->device->host; - struct ata_port *ap = ata_shost_to_port(host); + struct Scsi_Host *shost = cmd->device->host; + struct ata_port *ap; + struct ata_host *host; + struct ata_device *atadev; unsigned long flags; struct ata_queued_cmd *qc; - enum blk_eh_timer_return ret; + enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; DPRINTK("ENTER\n"); + host = ata_shost_to_host(shost); + atadev = ata_scsi_find_dev(host, cmd->device); + if (!atadev) + goto out; + ap = atadev->link->ap; + if (ap->ops->error_handler) { ret = BLK_EH_NOT_HANDLED; goto out; @@ -532,13 +540,12 @@ static void ata_eh_unload(struct ata_port *ap) * RETURNS: * Zero. */ -void ata_scsi_error(struct Scsi_Host *host) +static void __ata_scsi_error(struct Scsi_Host *shost, struct ata_port *ap) { - struct ata_port *ap = ata_shost_to_port(host); int i; unsigned long flags; - DPRINTK("ENTER\n"); + DPRINTK("ENTER, port_no %u\n", ap->port_no); /* synchronize with port task */ ata_port_flush_task(ap); @@ -575,7 +582,7 @@ void ata_scsi_error(struct Scsi_Host *host) if (ap->ops->lost_interrupt) ap->ops->lost_interrupt(ap); - list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { + list_for_each_entry_safe(scmd, tmp, &shost->eh_cmd_q, eh_entry) { struct ata_queued_cmd *qc; for (i = 0; i < ATA_MAX_QUEUE; i++) { @@ -698,7 +705,7 @@ void ata_scsi_error(struct Scsi_Host *host) * before EH completion, SCSI midlayer will * re-initiate EH. */ - host->host_eh_scheduled = 0; + shost->host_eh_scheduled = 0; spin_unlock_irqrestore(ap->lock, flags); } else { @@ -707,7 +714,7 @@ void ata_scsi_error(struct Scsi_Host *host) } /* finish or retry handled scmd's and clean up */ - WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q)); + WARN_ON(shost->host_failed || !list_empty(&shost->eh_cmd_q)); scsi_eh_flush_done_q(&ap->eh_done_q); @@ -733,6 +740,24 @@ void ata_scsi_error(struct Scsi_Host *host) DPRINTK("EXIT\n"); } +void ata_scsi_error(struct Scsi_Host *shost) +{ + struct ata_host *host = ata_shost_to_host(shost); + unsigned int i; + + DPRINTK("ENTER\n"); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->pflags & ATA_PFLAG_EH_PENDING) + __ata_scsi_error(shost, ap); + } + + DPRINTK("EXIT\n"); +} + + /** * ata_port_wait_eh - Wait for the currently pending EH to complete * @ap: Port to wait EH for @@ -761,7 +786,7 @@ void ata_port_wait_eh(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); /* make sure SCSI EH is complete */ - if (scsi_host_in_recovery(ap->scsi_host)) { + if (scsi_host_in_recovery(ap->host->scsi_host)) { msleep(10); goto retry; } @@ -901,7 +926,7 @@ void ata_port_schedule_eh(struct ata_port *ap) return; ata_eh_set_pending(ap, 1); - scsi_schedule_eh(ap->scsi_host); + scsi_schedule_eh(ap->host->scsi_host); DPRINTK("port EH scheduled\n"); } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 2733b0c..7aa6aa6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -58,10 +58,8 @@ static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); -static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, +static struct ata_device *__ata_scsi_find_dev(struct ata_host *, const struct scsi_device *scsidev); -static struct ata_device *ata_scsi_find_dev(struct ata_port *ap, - const struct scsi_device *scsidev); static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, unsigned int lun); @@ -136,6 +134,7 @@ static const char *ata_scsi_lpm_get(enum link_pm policy) return NULL; } +#if 0 static ssize_t ata_scsi_lpm_put(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -183,6 +182,7 @@ ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf) DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ata_scsi_lpm_show, ata_scsi_lpm_put); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); +#endif static ssize_t ata_scsi_park_show(struct device *device, struct device_attribute *attr, char *buf) @@ -190,19 +190,21 @@ static ssize_t ata_scsi_park_show(struct device *device, struct scsi_device *sdev = to_scsi_device(device); struct ata_port *ap; struct ata_link *link; + struct ata_host *host; struct ata_device *dev; unsigned long flags, now; unsigned int uninitialized_var(msecs); int rc = 0; - ap = ata_shost_to_port(sdev->host); + host = ata_shost_to_host(sdev->host); - spin_lock_irqsave(ap->lock, flags); - dev = ata_scsi_find_dev(ap, sdev); + spin_lock_irqsave(&host->lock, flags); + dev = ata_scsi_find_dev(host, sdev); if (!dev) { rc = -ENODEV; goto unlock; } + ap = dev->link->ap; if (dev->flags & ATA_DFLAG_NO_UNLOAD) { rc = -EOPNOTSUPP; goto unlock; @@ -218,7 +220,7 @@ static ssize_t ata_scsi_park_show(struct device *device, msecs = 0; unlock: - spin_unlock_irq(ap->lock); + spin_unlock_irq(&host->lock); return rc ? rc : snprintf(buf, 20, "%u\n", msecs); } @@ -230,6 +232,7 @@ static ssize_t ata_scsi_park_store(struct device *device, struct scsi_device *sdev = to_scsi_device(device); struct ata_port *ap; struct ata_device *dev; + struct ata_host *host; long int input; unsigned long flags; int rc; @@ -242,14 +245,15 @@ static ssize_t ata_scsi_park_store(struct device *device, input = ATA_TMOUT_MAX_PARK; } - ap = ata_shost_to_port(sdev->host); + host = ata_shost_to_host(sdev->host); - spin_lock_irqsave(ap->lock, flags); - dev = ata_scsi_find_dev(ap, sdev); + spin_lock_irqsave(&host->lock, flags); + dev = ata_scsi_find_dev(host, sdev); if (unlikely(!dev)) { rc = -ENODEV; goto unlock; } + ap = dev->link->ap; if (dev->class != ATA_DEV_ATA) { rc = -EOPNOTSUPP; goto unlock; @@ -276,7 +280,7 @@ static ssize_t ata_scsi_park_store(struct device *device, } } unlock: - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(&host->lock, flags); return rc ? rc : len; } @@ -291,6 +295,7 @@ static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); } +#if 0 static ssize_t ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -335,8 +340,9 @@ ata_scsi_activity_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); - struct ata_port *ap = ata_shost_to_port(sdev->host); - struct ata_device *atadev = ata_scsi_find_dev(ap, sdev); + struct ata_host *host = ata_shost_to_host(sdev->host); + struct ata_device *atadev = ata_scsi_find_dev(host, sdev); + struct ata_port *ap = atadev->ap; if (ap->ops->sw_activity_show && (ap->flags & ATA_FLAG_SW_ACTIVITY)) return ap->ops->sw_activity_show(atadev, buf); @@ -348,8 +354,9 @@ ata_scsi_activity_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct scsi_device *sdev = to_scsi_device(dev); - struct ata_port *ap = ata_shost_to_port(sdev->host); - struct ata_device *atadev = ata_scsi_find_dev(ap, sdev); + struct ata_host *host = ata_shost_to_host(sdev->host); + struct ata_device *atadev = ata_scsi_find_dev(host, sdev); + struct ata_port *ap = atadev->ap; enum sw_activity val; int rc; @@ -369,6 +376,7 @@ ata_scsi_activity_store(struct device *dev, struct device_attribute *attr, DEVICE_ATTR(sw_activity, S_IWUGO | S_IRUGO, ata_scsi_activity_show, ata_scsi_activity_store); EXPORT_SYMBOL_GPL(dev_attr_sw_activity); +#endif struct device_attribute *ata_common_sdev_attrs[] = { &dev_attr_unload_heads, @@ -425,10 +433,10 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, * RETURNS: * Zero on success, negative errno on error. */ -static int ata_get_identity(struct ata_port *ap, struct scsi_device *sdev, +static int ata_get_identity(struct ata_host *host, struct scsi_device *sdev, void __user *arg) { - struct ata_device *dev = ata_scsi_find_dev(ap, sdev); + struct ata_device *dev = ata_scsi_find_dev(host, sdev); u16 __user *dst = arg; char buf[40]; @@ -656,11 +664,18 @@ static int ata_ioc32(struct ata_port *ap) return 0; } -int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, +int ata_sas_scsi_ioctl(struct ata_host *host, struct scsi_device *scsidev, int cmd, void __user *arg) { int val = -EINVAL, rc = -EINVAL; unsigned long flags; + struct ata_port *ap; + struct ata_device *atadev; + + atadev = ata_scsi_find_dev(host, scsidev); + if (!atadev) + return -ENOENT; + ap = atadev->link->ap; switch (cmd) { case ATA_IOC_GET_IO32: @@ -688,7 +703,7 @@ int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, return rc; case HDIO_GET_IDENTITY: - return ata_get_identity(ap, scsidev, arg); + return ata_get_identity(host, scsidev, arg); case HDIO_DRIVE_CMD: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) @@ -711,7 +726,7 @@ EXPORT_SYMBOL_GPL(ata_sas_scsi_ioctl); int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) { - return ata_sas_scsi_ioctl(ata_shost_to_port(scsidev->host), + return ata_sas_scsi_ioctl(ata_shost_to_host(scsidev->host), scsidev, cmd, arg); } EXPORT_SYMBOL_GPL(ata_scsi_ioctl); @@ -1157,8 +1172,8 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, int ata_scsi_slave_config(struct scsi_device *sdev) { - struct ata_port *ap = ata_shost_to_port(sdev->host); - struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); + struct ata_host *host = ata_shost_to_host(sdev->host); + struct ata_device *dev = __ata_scsi_find_dev(host, sdev); int rc = 0; ata_scsi_sdev_config(sdev); @@ -1185,27 +1200,34 @@ int ata_scsi_slave_config(struct scsi_device *sdev) */ void ata_scsi_slave_destroy(struct scsi_device *sdev) { - struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_host *host = ata_shost_to_host(sdev->host); struct request_queue *q = sdev->request_queue; unsigned long flags; struct ata_device *dev; + bool new_eh = true; - if (!ap->ops->error_handler) - return; - - spin_lock_irqsave(ap->lock, flags); - dev = __ata_scsi_find_dev(ap, sdev); + spin_lock_irqsave(&host->lock, flags); + dev = __ata_scsi_find_dev(host, sdev); if (dev && dev->sdev) { + struct ata_port *ap = dev->link->ap; + + if (!ap->ops->error_handler) + new_eh = false; + + else { /* SCSI device already in CANCEL state, no need to offline it */ dev->sdev = NULL; dev->flags |= ATA_DFLAG_DETACH; ata_port_schedule_eh(ap); + } } - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(&host->lock, flags); - kfree(q->dma_drain_buffer); - q->dma_drain_buffer = NULL; - q->dma_drain_size = 0; + if (new_eh) { + kfree(q->dma_drain_buffer); + q->dma_drain_buffer = NULL; + q->dma_drain_size = 0; + } } /** @@ -1225,25 +1247,25 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) */ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) { - struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_host *host = ata_shost_to_host(sdev->host); struct ata_device *dev; unsigned long flags; if (queue_depth < 1 || queue_depth == sdev->queue_depth) return sdev->queue_depth; - dev = ata_scsi_find_dev(ap, sdev); + dev = ata_scsi_find_dev(host, sdev); if (!dev || !ata_dev_enabled(dev)) return sdev->queue_depth; /* NCQ enabled? */ - spin_lock_irqsave(ap->lock, flags); + spin_lock_irqsave(&host->lock, flags); dev->flags &= ~ATA_DFLAG_NCQ_OFF; if (queue_depth == 1 || !ata_ncq_enabled(dev)) { dev->flags |= ATA_DFLAG_NCQ_OFF; queue_depth = 1; } - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(&host->lock, flags); /* limit and apply queue depth */ queue_depth = min(queue_depth, sdev->host->can_queue); @@ -2690,21 +2712,20 @@ static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) return NULL; } -static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, +static struct ata_device *__ata_scsi_find_dev(struct ata_host *host, const struct scsi_device *scsidev) { int devno; + struct ata_port *ap; - /* skip commands not addressed to targets we simulate */ - if (!sata_pmp_attached(ap)) { - if (unlikely(scsidev->channel || scsidev->lun)) - return NULL; - devno = scsidev->id; - } else { - if (unlikely(scsidev->id || scsidev->lun)) - return NULL; - devno = scsidev->channel; - } + if (scsidev->channel > host->n_ports) + return NULL; + + ap = host->ports[scsidev->channel]; + if (ata_port_is_dummy(ap)) + return NULL; + + devno = scsidev->id; return ata_find_dev(ap, devno); } @@ -2725,10 +2746,10 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, * RETURNS: * Associated ATA device, or %NULL if not found. */ -static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) +struct ata_device * +ata_scsi_find_dev(struct ata_host *host, const struct scsi_device *scsidev) { - struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev); + struct ata_device *dev = __ata_scsi_find_dev(host, scsidev); if (unlikely(!dev || !ata_dev_enabled(dev))) return NULL; @@ -2983,15 +3004,13 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) * Prints the contents of a SCSI command via printk(). */ -static inline void ata_scsi_dump_cdb(struct ata_port *ap, - struct scsi_cmnd *cmd) +static inline void ata_scsi_dump_cdb(struct scsi_cmnd *cmd) { #ifdef ATA_DEBUG struct scsi_device *scsidev = cmd->device; u8 *scsicmd = cmd->cmnd; - DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ap->print_id, + DPRINTK("CDB (%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", scsidev->channel, scsidev->id, scsidev->lun, scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], @@ -3069,20 +3088,20 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, */ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - struct ata_port *ap; struct ata_device *dev; + struct ata_host *host; struct scsi_device *scsidev = cmd->device; struct Scsi_Host *shost = scsidev->host; int rc = 0; - ap = ata_shost_to_port(shost); + host = ata_shost_to_host(shost); spin_unlock(shost->host_lock); - spin_lock(ap->lock); + spin_lock(&host->lock); - ata_scsi_dump_cdb(ap, cmd); + ata_scsi_dump_cdb(cmd); - dev = ata_scsi_find_dev(ap, scsidev); + dev = ata_scsi_find_dev(host, scsidev); if (likely(dev)) rc = __ata_scsi_queuecmd(cmd, done, dev); else { @@ -3090,7 +3109,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) done(cmd); } - spin_unlock(ap->lock); + spin_unlock(&host->lock); spin_lock(shost->host_lock); return rc; } @@ -3217,56 +3236,43 @@ 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; + int rc; + struct Scsi_Host *shost; - rc = -ENOMEM; - shost = scsi_host_alloc(sht, sizeof(struct ata_port *)); - if (!shost) - goto err_alloc; + shost = scsi_host_alloc(sht, sizeof(struct ata_host *)); + if (!shost) + return -ENOMEM; - *(struct ata_port **)&shost->hostdata[0] = ap; - ap->scsi_host = shost; + *(struct ata_host **)&shost->hostdata[0] = host; + host->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; + shost->transportt = &ata_scsi_transport_template; + shost->unique_id = host->print_id; + shost->max_id = 32; + shost->max_lun = 1; + shost->max_channel = 32; + shost->max_cmd_len = 16; - /* Schedule policy is determined by ->qc_defer() - * callback and it needs to see every deferred qc. - * Set host_blocked to 1 to prevent SCSI midlayer from - * automatically deferring requests. - */ - shost->max_host_blocked = 1; + /* Schedule policy is determined by ->qc_defer() + * callback and it needs to see every deferred qc. + * Set host_blocked to 1 to prevent SCSI midlayer from + * automatically deferring requests. + */ + shost->max_host_blocked = 1; - rc = scsi_add_host(ap->scsi_host, ap->host->dev); - if (rc) - goto err_add; + rc = scsi_add_host(shost, host->dev); + if (rc) { + scsi_host_put(shost); + return rc; } 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, int sync) { int tries = 5; + struct ata_host *host = ap->host; struct ata_device *last_failed_dev = NULL; struct ata_link *link; struct ata_device *dev; @@ -3278,7 +3284,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) ata_for_each_link(link, ap, EDGE) { ata_for_each_dev(dev, link, ENABLED) { struct scsi_device *sdev; - int channel = 0, id = 0; + int id = 0; if (dev->sdev) continue; @@ -3286,9 +3292,10 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) if (ata_is_host_link(link)) id = dev->devno; else - channel = link->pmp; + id = link->pmp; - sdev = __scsi_add_device(ap->scsi_host, channel, id, 0, + sdev = __scsi_add_device(host->scsi_host, + ap->port_no, id, 0, NULL); if (!IS_ERR(sdev)) { dev->sdev = sdev; @@ -3376,6 +3383,7 @@ int ata_scsi_offline_dev(struct ata_device *dev) static void ata_scsi_remove_dev(struct ata_device *dev) { struct ata_port *ap = dev->link->ap; + struct ata_host *host = ap->host; struct scsi_device *sdev; unsigned long flags; @@ -3385,7 +3393,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev) * be removed if there is __scsi_device_get() interface which * increments reference counts regardless of device state. */ - mutex_lock(&ap->scsi_host->scan_mutex); + mutex_lock(&host->scsi_host->scan_mutex); spin_lock_irqsave(ap->lock, flags); /* clearing dev->sdev is protected by host lock */ @@ -3411,7 +3419,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev) } spin_unlock_irqrestore(ap->lock, flags); - mutex_unlock(&ap->scsi_host->scan_mutex); + mutex_unlock(&host->scsi_host->scan_mutex); if (sdev) { ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n", @@ -3517,25 +3525,28 @@ void ata_scsi_hotplug(struct work_struct *work) static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, unsigned int lun) { - struct ata_port *ap = ata_shost_to_port(shost); + struct ata_port *ap; + struct ata_host *host = ata_shost_to_host(shost); unsigned long flags; int devno, rc = 0; + if (channel == SCAN_WILD_CARD) + ap = host->ports[0]; + else { + if (channel > host->n_ports) + return -EINVAL; + ap = host->ports[channel]; + } + if (!ap->ops->error_handler) return -EOPNOTSUPP; if (lun != SCAN_WILD_CARD && lun) return -EINVAL; - if (!sata_pmp_attached(ap)) { - if (channel != SCAN_WILD_CARD && channel) - return -EINVAL; - devno = id; - } else { - if (id != SCAN_WILD_CARD && id) - return -EINVAL; - devno = channel; - } + if (id != SCAN_WILD_CARD && id) + return -EINVAL; + devno = id; spin_lock_irqsave(ap->lock, flags); @@ -3749,7 +3760,7 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), { int rc = 0; - ata_scsi_dump_cdb(ap, cmd); + ata_scsi_dump_cdb(cmd); if (likely(ata_dev_enabled(ap->link.device))) rc = __ata_scsi_queuecmd(cmd, done, ap->link.device); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 89a1e00..af890b4 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -205,4 +205,7 @@ extern u8 ata_irq_on(struct ata_port *ap); extern void ata_pio_task(struct work_struct *work); #endif /* CONFIG_ATA_SFF */ +struct ata_device * +ata_scsi_find_dev(struct ata_host *host, const struct scsi_device *scsidev); + #endif /* __LIBATA_H__ */ diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index e155011..758df0b 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -375,6 +375,7 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev, ha->dev, sata_port_info.flags, &sas_sata_ops); + found_dev->sata_dev.ata_host.scsi_host = shost; ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host, &sata_port_info, shost); @@ -385,7 +386,6 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev, ap->private_data = found_dev; ap->cbl = ATA_CBL_SATA; - ap->scsi_host = shost; found_dev->sata_dev.ap = ap; return 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index 3d501db..2ea4dce 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -507,10 +507,12 @@ struct ata_ioports { #endif /* CONFIG_ATA_SFF */ struct ata_host { + struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ spinlock_t lock; struct device *dev; void __iomem * const *iomap; unsigned int n_ports; + unsigned int print_id; /* user visible unique host ID */ void *private_data; struct ata_port_operations *ops; unsigned long flags; @@ -690,7 +692,6 @@ struct ata_link { }; struct ata_port { - struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ struct ata_port_operations *ops; spinlock_t *lock; /* Flags owned by the EH context. Only EH should touch these once the @@ -947,7 +948,7 @@ extern void ata_host_init(struct ata_host *, struct device *, extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev, +extern int ata_sas_scsi_ioctl(struct ata_host *, struct scsi_device *dev, int cmd, void __user *arg); extern void ata_sas_port_destroy(struct ata_port *); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, @@ -1472,9 +1473,9 @@ static inline unsigned int __ac_err_mask(u8 status) return mask; } -static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) +static inline struct ata_host *ata_shost_to_host(struct Scsi_Host *host) { - return *(struct ata_port **)&host->hostdata[0]; + return *(struct ata_host **)&host->hostdata[0]; } static inline int ata_check_ready(u8 status)