summaryrefslogtreecommitdiff
path: root/drivers/scsi/scsi_transport_sas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r--drivers/scsi/scsi_transport_sas.c97
1 files changed, 79 insertions, 18 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index d704c484a251..d69c7c444a31 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -40,6 +40,8 @@
#include <scsi/scsi_transport_sas.h>
#include "scsi_sas_internal.h"
+#include "scsi_priv.h"
+
struct sas_host_attrs {
struct list_head rphy_list;
struct mutex lock;
@@ -197,7 +199,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
}
if (rphy) {
- q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev),
+ q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev), NULL,
sas_smp_dispatch, NULL, 0);
if (IS_ERR(q))
return PTR_ERR(q);
@@ -206,7 +208,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
char name[20];
snprintf(name, sizeof(name), "sas_host%d", shost->host_no);
- q = bsg_setup_queue(&shost->shost_gendev, name,
+ q = bsg_setup_queue(&shost->shost_gendev, name, NULL,
sas_smp_dispatch, NULL, 0);
if (IS_ERR(q))
return PTR_ERR(q);
@@ -416,6 +418,29 @@ unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
}
EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
+/**
+ * sas_ata_ncq_prio_supported - Check for ATA NCQ command priority support
+ * @sdev: SCSI device
+ *
+ * Check if an ATA device supports NCQ priority using VPD page 89h (ATA
+ * Information). Since this VPD page is implemented only for ATA devices,
+ * this function always returns false for SCSI devices.
+ */
+bool sas_ata_ncq_prio_supported(struct scsi_device *sdev)
+{
+ struct scsi_vpd *vpd;
+ bool ncq_prio_supported = false;
+
+ rcu_read_lock();
+ vpd = rcu_dereference(sdev->vpd_pg89);
+ if (vpd && vpd->len >= 214)
+ ncq_prio_supported = (vpd->data[213] >> 4) & 1;
+ rcu_read_unlock();
+
+ return ncq_prio_supported;
+}
+EXPORT_SYMBOL_GPL(sas_ata_ncq_prio_supported);
+
/*
* SAS Phy attributes
*/
@@ -865,7 +890,8 @@ static void sas_port_delete_link(struct sas_port *port,
sysfs_remove_link(&phy->dev.kobj, "port");
}
-/** sas_port_alloc - allocate and initialize a SAS port structure
+/**
+ * sas_port_alloc - allocate and initialize a SAS port structure
*
* @parent: parent device
* @port_id: port number
@@ -874,7 +900,7 @@ static void sas_port_delete_link(struct sas_port *port,
* below the device specified by @parent which must be either a Scsi_Host
* or a sas_expander_device.
*
- * Returns %NULL on error
+ * Returns: %NULL on error
*/
struct sas_port *sas_port_alloc(struct device *parent, int port_id)
{
@@ -909,7 +935,8 @@ struct sas_port *sas_port_alloc(struct device *parent, int port_id)
}
EXPORT_SYMBOL(sas_port_alloc);
-/** sas_port_alloc_num - allocate and initialize a SAS port structure
+/**
+ * sas_port_alloc_num - allocate and initialize a SAS port structure
*
* @parent: parent device
*
@@ -919,7 +946,7 @@ EXPORT_SYMBOL(sas_port_alloc);
* the device tree below the device specified by @parent which must be
* either a Scsi_Host or a sas_expander_device.
*
- * Returns %NULL on error
+ * Returns: %NULL on error
*/
struct sas_port *sas_port_alloc_num(struct device *parent)
{
@@ -1658,32 +1685,66 @@ int scsi_is_sas_rphy(const struct device *dev)
}
EXPORT_SYMBOL(scsi_is_sas_rphy);
-
-/*
- * SCSI scan helper
- */
-
-static int sas_user_scan(struct Scsi_Host *shost, uint channel,
- uint id, u64 lun)
+static void scan_channel_zero(struct Scsi_Host *shost, uint id, u64 lun)
{
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
struct sas_rphy *rphy;
- mutex_lock(&sas_host->lock);
list_for_each_entry(rphy, &sas_host->rphy_list, list) {
if (rphy->identify.device_type != SAS_END_DEVICE ||
rphy->scsi_target_id == -1)
continue;
- if ((channel == SCAN_WILD_CARD || channel == 0) &&
- (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
+ if (id == SCAN_WILD_CARD || id == rphy->scsi_target_id) {
scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,
lun, SCSI_SCAN_MANUAL);
}
}
- mutex_unlock(&sas_host->lock);
+}
- return 0;
+/*
+ * SCSI scan helper
+ */
+
+static int sas_user_scan(struct Scsi_Host *shost, uint channel,
+ uint id, u64 lun)
+{
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+ int res = 0;
+ int i;
+
+ switch (channel) {
+ case 0:
+ mutex_lock(&sas_host->lock);
+ scan_channel_zero(shost, id, lun);
+ mutex_unlock(&sas_host->lock);
+ break;
+
+ case SCAN_WILD_CARD:
+ mutex_lock(&sas_host->lock);
+ scan_channel_zero(shost, id, lun);
+ mutex_unlock(&sas_host->lock);
+
+ for (i = 1; i <= shost->max_channel; i++) {
+ res = scsi_scan_host_selected(shost, i, id, lun,
+ SCSI_SCAN_MANUAL);
+ if (res)
+ goto exit_scan;
+ }
+ break;
+
+ default:
+ if (channel < shost->max_channel) {
+ res = scsi_scan_host_selected(shost, channel, id, lun,
+ SCSI_SCAN_MANUAL);
+ } else {
+ res = -EINVAL;
+ }
+ break;
+ }
+
+exit_scan:
+ return res;
}