From 6bdfcb35a074d9c58c180f8c512706faf7d6c7cb Mon Sep 17 00:00:00 2001
From: peter chang <dpf@google.com>
Date: Tue, 20 Dec 2016 09:48:45 -0800
Subject: [PATCH] set a base index for libsas based ata devices
libsas hosts allow multiple links, but when the controller
supports SATA devices control is handed to libata. this means
that an attached scsi device will be setup properly, but device
management requests and sysfs futzing don't get routed correctly
because the device lookup fails.
Tested:
- pre-patch:
jkgg70:~# ls -d /sys/block/sd*
/sys/block/sda
jkgg70:~# modprobe pm80xx
jkgg70:~# cat /sys/block/sdb/device/queue_depth
31
jkgg70:~# echo 1 > /sys/block/sdb/device/queue_depth
jkgg70:~# cat /sys/block/sdb/device/queue_depth
31
- post-patch:
jkgg70:~# modprobe pm80xx
jkgg70:~# cat /sys/block/sdb/device/queue_depth
31
jkgg70:~# echo 1 > /sys/block/sdb/device/queue_depth
jkgg70:~# cat /sys/block/sdb/device/queue_depth
1
Signed-off-by: peter chang <dpf@google.com>
---
drivers/ata/libata-scsi.c | 33 ++++++++++++++++++++++++++++++++-
drivers/scsi/libsas/sas_scsi_host.c | 4 ++++
include/linux/libata.h | 3 +++
3 files changed, 39 insertions(+), 1 deletion(-)
@@ -1088,7 +1088,7 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
* passthrough command, so we use the following sense data:
* sk = RECOVERED ERROR
* asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
- *
+ *
*
* LOCKING:
* None.
@@ -3052,6 +3052,16 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
{
+ /* adjust if this port is behind a libsas host rather than a
+ * direct libata host. warn and fail if somehow we got out of
+ * sync and we've a negative device number.
+ */
+ devno -= ap->link.sas_host_base;
+ if (unlikely(devno < 0)) {
+ WARN_ON(devno < 0);
+ return NULL;
+ }
+
if (!sata_pmp_attached(ap)) {
if (likely(devno < ata_link_max_devices(&ap->link)))
return &ap->link.device[devno];
@@ -4332,6 +4342,27 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
}
/**
+ * ata_sas_set_link_base - set the libata link's 'base' because
+ * libsas hosts have more ports / links.
+ * @ap: ATA port to which the target is attached
+ * @starget: SCSI target being attached
+ */
+void ata_sas_set_link_base(struct ata_port *ap, struct scsi_target *starget)
+{
+ unsigned int host_base;
+
+ if (!sata_pmp_attached(ap)) {
+ WARN_ON(starget->channel);
+ host_base = starget->id;
+ } else {
+ WARN_ON(starget->id);
+ host_base = starget->channel;
+ }
+ ap->link.sas_host_base = host_base;
+}
+EXPORT_SYMBOL_GPL(ata_sas_set_link_base);
+
+/**
* ata_scsi_simulate - simulate SCSI command on ATA device
* @dev: the target device
* @cmd: SCSI command being sent to device.
@@ -859,6 +859,10 @@ int sas_target_alloc(struct scsi_target *starget)
kref_get(&found_dev->kref);
starget->hostdata = found_dev;
+
+ if (dev_is_sata(found_dev))
+ ata_sas_set_link_base(found_dev->sata_dev.ap, starget);
+
return 0;
}
@@ -791,6 +791,7 @@ struct ata_acpi_gtm {
struct ata_link {
struct ata_port *ap;
int pmp; /* port multiplier port # */
+ int sas_host_base; /* host relative id */
struct device tdev;
unsigned int active_tag; /* active tag on this link */
@@ -1130,6 +1131,8 @@ extern int ata_sas_port_start(struct ata_port *ap);
extern void ata_sas_port_stop(struct ata_port *ap);
extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap);
+extern void ata_sas_set_link_base(struct ata_port *ap,
+ struct scsi_target *starget);
extern int sata_scr_valid(struct ata_link *link);
extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
--
2.8.0.rc3.226.g39d4020