ata: ahci: find eSATA ports and flag them as removable
authorManuel Lauss <manuel.lauss@gmail.com>
Wed, 30 Sep 2015 19:10:25 +0000 (21:10 +0200)
committerTejun Heo <tj@kernel.org>
Wed, 30 Sep 2015 21:37:55 +0000 (17:37 -0400)
If the AHCI ports' HPCP or ESP bits are set, the port
should be considered external (e.g. eSATA) and is marked
as removable.  Userspace tools like udisks then treat it
like an usb drive.

With this patch applied, when I plug a drive into the esata port,
KDE pops up a window asking what to do with the drives(s), just
like it does for any random USB stick.

Removability is indicated to the upper layers by way of the
SCSI RMB bit, as I haven't found another way to signal
userspace to treat a sata disk like any usb stick.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
drivers/ata/ahci.h
drivers/ata/libahci.c
drivers/ata/libata-scsi.c
include/linux/libata.h

index 5b8e8a0fab487a8fdce58066c347df6759b31bee..45586c1dbbdc1e225947c09e200bf5b2c2296a15 100644 (file)
@@ -181,6 +181,8 @@ enum {
        PORT_CMD_ALPE           = (1 << 26), /* Aggressive Link PM enable */
        PORT_CMD_ATAPI          = (1 << 24), /* Device is ATAPI */
        PORT_CMD_FBSCP          = (1 << 22), /* FBS Capable Port */
+       PORT_CMD_ESP            = (1 << 21), /* External Sata Port */
+       PORT_CMD_HPCP           = (1 << 18), /* HotPlug Capable Port */
        PORT_CMD_PMP            = (1 << 17), /* PMP attached */
        PORT_CMD_LIST_ON        = (1 << 15), /* cmd list DMA engine running */
        PORT_CMD_FIS_ON         = (1 << 14), /* FIS DMA engine running */
index d256a66158be838bb7b312dcda96f6ecad97e332..2fa551a5146e3fda5044d110cb41f90c7dab0ad7 100644 (file)
@@ -1117,6 +1117,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
                           int port_no, void __iomem *mmio,
                           void __iomem *port_mmio)
 {
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        const char *emsg = NULL;
        int rc;
        u32 tmp;
@@ -1138,6 +1139,12 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
                writel(tmp, port_mmio + PORT_IRQ_STAT);
 
        writel(1 << port_no, mmio + HOST_IRQ_STAT);
+
+       /* mark esata ports */
+       tmp = readl(port_mmio + PORT_CMD);
+       if ((tmp & PORT_CMD_HPCP) ||
+           ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)))
+               ap->pflags |= ATA_PFLAG_EXTERNAL;
 }
 
 void ahci_init_controller(struct ata_host *host)
index 0d7f0da3a26929622080f94a2a3125c63676999e..183a57bff935dc3356efb8266b6440e2072c2313 100644 (file)
@@ -2015,8 +2015,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
 
        VPRINTK("ENTER\n");
 
-       /* set scsi removable (RMB) bit per ata bit */
-       if (ata_id_removable(args->id))
+       /* set scsi removable (RMB) bit per ata bit, or if the
+        * AHCI port says it's external (Hotplug-capable, eSATA).
+        */
+       if (ata_id_removable(args->id) ||
+           (args->dev->link->ap->pflags & ATA_PFLAG_EXTERNAL))
                hdr[1] |= (1 << 7);
 
        if (args->dev->class == ATA_DEV_ZAC) {
index c9cfbcdb8d140e2f136b724501a064a25a766fb3..83577f8fd15bcd0f8693ef6a1a2a9fb216b32b2b 100644 (file)
@@ -254,6 +254,7 @@ enum {
 
        ATA_PFLAG_PIO32         = (1 << 20),  /* 32bit PIO */
        ATA_PFLAG_PIO32CHANGE   = (1 << 21),  /* 32bit PIO can be turned on/off */
+       ATA_PFLAG_EXTERNAL      = (1 << 22),  /* eSATA/external port */
 
        /* struct ata_queued_cmd flags */
        ATA_QCFLAG_ACTIVE       = (1 << 0), /* cmd not yet ack'd to scsi lyer */