]> err.no Git - linux-2.6/commitdiff
[PATCH] libata-hp-prep: make some ata_device fields persistent
authorTejun Heo <htejun@gmail.com>
Wed, 31 May 2006 09:27:32 +0000 (18:27 +0900)
committerTejun Heo <htejun@gmail.com>
Wed, 31 May 2006 09:27:32 +0000 (18:27 +0900)
Lifetimes of some fields span over device plugging/unplugging.  This
patch moves such persistent fields to the top of ata_device and
separate them with ATA_DEVICE_CLEAR_OFFSET.  Fields above the offset
are initialized once during host initializatino while all other fields
are cleared before hotplugging.  Currently ->ap, devno and part of
flags are persistent.

Note that flags is partially cleared while holding host_set lock.
This is to synchronize with later warm plug implementation which will
record hotplug request in dev->flags.

Signed-off-by: Tejun Heo <htejun@gmail.com>
drivers/scsi/libata-core.c
include/linux/libata.h

index 8fda8228159ce3f809080476505ddfc01a27d58d..a07ab77d32d6d7cd61d13c8ce2b5a1cc6f3a2f09 100644 (file)
@@ -5153,9 +5153,18 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
 void ata_dev_init(struct ata_device *dev)
 {
        struct ata_port *ap = dev->ap;
+       unsigned long flags;
+
+       /* High bits of dev->flags are used to record warm plug
+        * requests which occur asynchronously.  Synchronize using
+        * host_set lock.
+        */
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       dev->flags &= ~ATA_DFLAG_INIT_MASK;
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
-       memset((void *)dev, 0, sizeof(*dev));
-       dev->devno = dev - ap->device;
+       memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
+              sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
        dev->pio_mask = UINT_MAX;
        dev->mwdma_mask = UINT_MAX;
        dev->udma_mask = UINT_MAX;
@@ -5218,6 +5227,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
                dev->ap = ap;
+               dev->devno = i;
                ata_dev_init(dev);
        }
 
index d4a668cf143b25048ee7dd002ade681b6d3e1a0d..aa14eda0656c62f49495212fa0bd2b4238825d2e 100644 (file)
@@ -130,6 +130,7 @@ enum {
        ATA_DFLAG_CFG_MASK      = (1 << 8) - 1,
 
        ATA_DFLAG_PIO           = (1 << 8), /* device currently in PIO mode */
+       ATA_DFLAG_INIT_MASK     = (1 << 16) - 1,
 
        ATA_DFLAG_DETACH        = (1 << 16),
        ATA_DFLAG_DETACHED      = (1 << 17),
@@ -410,10 +411,11 @@ struct ata_ering {
 
 struct ata_device {
        struct ata_port         *ap;
-       u64                     n_sectors;      /* size of device, if ATA */
+       unsigned int            devno;          /* 0 or 1 */
        unsigned long           flags;          /* ATA_DFLAG_xxx */
+       /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
+       u64                     n_sectors;      /* size of device, if ATA */
        unsigned int            class;          /* ATA_DEV_xxx */
-       unsigned int            devno;          /* 0 or 1 */
        u16                     id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
        u8                      pio_mode;
        u8                      dma_mode;
@@ -439,6 +441,11 @@ struct ata_device {
        struct ata_ering        ering;
 };
 
+/* Offset into struct ata_device.  Fields above it are maintained
+ * acress device init.  Fields below are zeroed.
+ */
+#define ATA_DEVICE_CLEAR_OFFSET                offsetof(struct ata_device, n_sectors)
+
 struct ata_eh_info {
        struct ata_device       *dev;           /* offending device */
        u32                     serror;         /* SError from LLDD */