[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20090422090929.GA14928@havoc.gtf.org>
Date: Wed, 22 Apr 2009 05:09:29 -0400
From: Jeff Garzik <jeff@...zik.org>
To: linux-ide@...r.kernel.org, linux-scsi@...r.kernel.org
Cc: LKML <linux-kernel@...r.kernel.org>
Subject: [PATCH] libata: rewrite SCSI host scheme to be one per ATA host
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)
View attachment "dmesg.txt" of type "text/plain" (43768 bytes)
Powered by blists - more mailing lists