Re: libata/sata_sil24 cache alignment problem?

2008-02-13 Thread Mark Mason
Alan Cox [EMAIL PROTECTED] wrote:

  Has anyone else reported a problem like this?  It requires
  non-coherent DMA, and a lack of a cache invalidate instruction, and
  one of the drivers that has this problem (it looks like sata_qstor
  does too, I haven't looked at others), so maybe that doesn't cover
  any other architectures.
 
 Nobody has, not even PA-RISC which is normally guaranteed to make life
 miserable in the caching area but I agree entirely with your diagnosis
 and that buffer should indeed be marked cache aligned
 
  I can provide a patch if you're interested.
 
 Please do.

Here it is.  I'd appreciate it if someone could sanity check where I'm
freeing the buffer.  It works, but I don't know the code well enough
to know if this covers all cases.

I'm counting on kmalloc to return a cache aligned buffer.  I found
some reason to think it does, but I don't remember offhand what that
reason was, or if it's configurable per-architecture.  The buffer has
to be both physically and virtually contiguous, I was tempted to just
allocate a page and waste some space but we've got 64K pages, so I'm a
bit more sensitive about that.



*** drivers/scsi/libata-core.c  2008-02-13 13:34:32.141489000 -0500
--- drivers/scsi/libata-core.c.orig 2008-02-13 13:29:35.62036 -0500
***
*** 5335,5369 
}
  
host = scsi_host_alloc(ent-sht, sizeof(struct ata_port));
if (!host)
return NULL;
  
host-transportt = ata_scsi_transport_template;
  
ap = ata_shost_to_port(host);
  
-   ap-sector_buf = kmalloc(ATA_SECT_SIZE, GFP_KERNEL);
-   if (!ap-sector_buf)
-   goto err_out;
- 
ata_host_init(ap, host, host_set, ent, port_no);
  
rc = ap-ops-port_start(ap);
if (rc)
goto err_out;
  
return ap;
  
  err_out:
-   if (ap-sector_buf)
-   kfree(ap-sector_buf);
scsi_host_put(host);
return NULL;
  }
  
  /**
   *ata_device_add - Register hardware device with ATA and SCSI layers
   *@ent: Probe information describing hardware device to be registered
   *
   *This function processes the information provided in the probe
   *information struct @ent, allocates the necessary ATA and SCSI
--- 5335,5363 
***
*** 5602,5645 
   *Unregister all objects associated with this host set. Free those
   *objects.
   *
   *LOCKING:
   *Inherited from calling layer (may sleep).
   */
  
  void ata_host_set_remove(struct ata_host_set *host_set)
  {
unsigned int i;
-   u8 *sector_buf;
  
for (i = 0; i  host_set-n_ports; i++)
ata_port_detach(host_set-ports[i]);
  
free_irq(host_set-irq, host_set);
  
for (i = 0; i  host_set-n_ports; i++) {
struct ata_port *ap = host_set-ports[i];
  
ata_scsi_release(ap-host);
  
if ((ap-flags  ATA_FLAG_NO_LEGACY) == 0) {
struct ata_ioports *ioaddr = ap-ioaddr;
  
if (ioaddr-cmd_addr == 0x1f0)
release_region(0x1f0, 8);
else if (ioaddr-cmd_addr == 0x170)
release_region(0x170, 8);
}
  
-   sector_buf = ap-sector_buf;
scsi_host_put(ap-host);
-   kfree(sector_buf);
}
  
if (host_set-ops-host_stop)
host_set-ops-host_stop(host_set);
  
kfree(host_set);
  }
  
  /**
   *ata_scsi_release - SCSI layer callback hook for host unload
--- 5596,5636 
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-13 Thread Mark Mason
Alan Cox [EMAIL PROTECTED] wrote:

  Has anyone else reported a problem like this?  It requires
  non-coherent DMA, and a lack of a cache invalidate instruction, and
  one of the drivers that has this problem (it looks like sata_qstor
  does too, I haven't looked at others), so maybe that doesn't cover
  any other architectures.
 
 Nobody has, not even PA-RISC which is normally guaranteed to make life
 miserable in the caching area but I agree entirely with your diagnosis
 and that buffer should indeed be marked cache aligned
 
  I can provide a patch if you're interested.
 
 Please do.

Oops, sorry, I left a file out of that diff.  Here it is again...

*** drivers/scsi/libata-core.c  2008-02-13 13:34:32.141489000 -0500
--- drivers/scsi/libata-core.c.orig 2008-02-13 13:29:35.62036 -0500
***
*** 5335,5369 
}
  
host = scsi_host_alloc(ent-sht, sizeof(struct ata_port));
if (!host)
return NULL;
  
host-transportt = ata_scsi_transport_template;
  
ap = ata_shost_to_port(host);
  
-   ap-sector_buf = kmalloc(ATA_SECT_SIZE, GFP_KERNEL);
-   if (!ap-sector_buf)
-   goto err_out;
- 
ata_host_init(ap, host, host_set, ent, port_no);
  
rc = ap-ops-port_start(ap);
if (rc)
goto err_out;
  
return ap;
  
  err_out:
-   if (ap-sector_buf)
-   kfree(ap-sector_buf);
scsi_host_put(host);
return NULL;
  }
  
  /**
   *ata_device_add - Register hardware device with ATA and SCSI layers
   *@ent: Probe information describing hardware device to be registered
   *
   *This function processes the information provided in the probe
   *information struct @ent, allocates the necessary ATA and SCSI
--- 5335,5363 
***
*** 5602,5645 
   *Unregister all objects associated with this host set. Free those
   *objects.
   *
   *LOCKING:
   *Inherited from calling layer (may sleep).
   */
  
  void ata_host_set_remove(struct ata_host_set *host_set)
  {
unsigned int i;
-   u8 *sector_buf;
  
for (i = 0; i  host_set-n_ports; i++)
ata_port_detach(host_set-ports[i]);
  
free_irq(host_set-irq, host_set);
  
for (i = 0; i  host_set-n_ports; i++) {
struct ata_port *ap = host_set-ports[i];
  
ata_scsi_release(ap-host);
  
if ((ap-flags  ATA_FLAG_NO_LEGACY) == 0) {
struct ata_ioports *ioaddr = ap-ioaddr;
  
if (ioaddr-cmd_addr == 0x1f0)
release_region(0x1f0, 8);
else if (ioaddr-cmd_addr == 0x170)
release_region(0x170, 8);
}
  
-   sector_buf = ap-sector_buf;
scsi_host_put(ap-host);
-   kfree(sector_buf);
}
  
if (host_set-ops-host_stop)
host_set-ops-host_stop(host_set);
  
kfree(host_set);
  }
  
  /**
   *ata_scsi_release - SCSI layer callback hook for host unload
--- 5596,5636 
*** include/linux/libata.h  2008-02-13 10:51:39.151202000 -0500
--- include/linux/libata.h.orig 2008-02-13 13:50:26.531572000 -0500
***
*** 550,570 
  
u32 msg_enable;
struct list_headeh_done_q;
wait_queue_head_t   eh_wait_q;
  
pm_message_tpm_mesg;
int *pm_result;
  
void*private_data;
  
!   u8  *sector_buf; /* owned by EH */
  };
  
  struct ata_port_operations {
void (*port_disable) (struct ata_port *);
  
void (*dev_config) (struct ata_port *, struct ata_device *);
  
void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (struct ata_port *, struct ata_device *);
unsigned long (*mode_filter) (const struct ata_port *, struct 
ata_device *, unsigned long);
--- 550,570 
  
u32 msg_enable;
struct list_headeh_done_q;
wait_queue_head_t   eh_wait_q;
  
pm_message_tpm_mesg;
int *pm_result;
  
void*private_data;
  
!   u8  sector_buf[ATA_SECT_SIZE]; /* owned by EH */
  };
  
  struct ata_port_operations {
void (*port_disable) (struct ata_port *);
  
void (*dev_config) (struct ata_port *, struct ata_device *);
  
void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (struct ata_port *, struct ata_device *);
unsigned long (*mode_filter) (const struct ata_port *, struct 
ata_device *, unsigned long);
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  

Re: libata/sata_sil24 cache alignment problem?

2008-02-13 Thread Alan Cox
O I'm counting on kmalloc to return a cache aligned buffer.  I found
 some reason to think it does, but I don't remember offhand what that

Its defined to

 reason was, or if it's configurable per-architecture.  The buffer has
 to be both physically and virtually contiguous, I was tempted to just
 allocate a page and waste some space but we've got 64K pages, so I'm a
 bit more sensitive about that.

Ok I was expecting a different approach if you mark the field with the
magic  cacheline_aligned tag after it (ie int foo blah_aligned;)
the compiler should align it all for you , which is probably cleaner if
it works.
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-13 Thread Mark Mason
Alan Cox [EMAIL PROTECTED] wrote:

 O I'm counting on kmalloc to return a cache aligned buffer.  I found
  some reason to think it does, but I don't remember offhand what that
 
 Its defined to
 
  reason was, or if it's configurable per-architecture.  The buffer has
  to be both physically and virtually contiguous, I was tempted to just
  allocate a page and waste some space but we've got 64K pages, so I'm a
  bit more sensitive about that.
 
 Ok I was expecting a different approach if you mark the field with the
 magic  cacheline_aligned tag after it (ie int foo blah_aligned;)
 the compiler should align it all for you , which is probably cleaner if
 it works.

I hadn't considered that approach due to the way the ata_port is allocated:

 libata-core.c:
 host = scsi_host_alloc(ent-sht, sizeof(struct ata_port));
 
 hosts.c:
 struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int 
 privsize)
 {
 shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
 }

The ata_port allocation is tacked onto the end of the Scsi_Host
allocation, so the start of ata_port will only be cache aligned if the
end of the Scsi_Host struct is, although that would be easy enough to
fix since it's currently aligned to an unsigned long boundary.

I like that approach better, since it's clearer what the intent is,
and it's easier.  Is there any other way that the ata_port struct
might be used that would invalidate this?  This one issue is the
extent of my knowledge of libata.
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-13 Thread Alan Cox
 I hadn't considered that approach due to the way the ata_port is allocated:
 
  libata-core.c:
  host = scsi_host_alloc(ent-sht, sizeof(struct ata_port));
  
  hosts.c:
  struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int 
  privsize)
  {
  shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
  }
 
 The ata_port allocation is tacked onto the end of the Scsi_Host
 allocation, so the start of ata_port will only be cache aligned if the
 end of the Scsi_Host struct is, although that would be easy enough to
 fix since it's currently aligned to an unsigned long boundary.

You are right.

 I like that approach better, since it's clearer what the intent is,
 and it's easier.  Is there any other way that the ata_port struct
 might be used that would invalidate this?  

I can't think of one. The object lifetime is right - the ata_port is
created before the port buffer is used and destroyed after it is finished
(obviously or embedding it in the struct wouldn't work either)

Alan
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-13 Thread Tejun Heo
Alan Cox wrote:
 I hadn't considered that approach due to the way the ata_port is allocated:

 libata-core.c:
 host = scsi_host_alloc(ent-sht, sizeof(struct ata_port));

 hosts.c:
 struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int 
 privsize)
 {
 shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
 }
 The ata_port allocation is tacked onto the end of the Scsi_Host
 allocation, so the start of ata_port will only be cache aligned if the
 end of the Scsi_Host struct is, although that would be easy enough to
 fix since it's currently aligned to an unsigned long boundary.
 
 You are right.

For recent kernels, ata_port is allocated separately so
cacheline_aligned should be enough.

 I like that approach better, since it's clearer what the intent is,

But, yeah, allocating separately is probably safer.

 and it's easier.  Is there any other way that the ata_port struct
 might be used that would invalidate this?  
 
 I can't think of one. The object lifetime is right - the ata_port is
 created before the port buffer is used and destroyed after it is finished
 (obviously or embedding it in the struct wouldn't work either)

I'll prep a patch for the current kernel.  Hmmm... This means that any
DMA buffer should be aligned to cacheline.  Block layer DMA alignment
helpers should probably take this into consideration and we better add
warnings to dma map functions.  This only affects DMA-to-memory, right?

Thanks.

-- 
tejun
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-12 Thread Alan Cox
 I tell you what ... find me a parisc box that actually has IDE and we
 might have told you ...

The NS87415 variant IDE has been tested on parisc and didn't blow up -
must just be lucky.

 (actually, the pa8800's have IDE CD's on a cmd640 chip, but that oopses
 on boot for no reason we've tracked yet).

With libata, old IDE or both ? and what does the oops look like ?
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-12 Thread James Bottomley

On Wed, 2008-02-13 at 02:13 +, Alan Cox wrote:
  I tell you what ... find me a parisc box that actually has IDE and we
  might have told you ...
 
 The NS87415 variant IDE has been tested on parisc and didn't blow up -
 must just be lucky.

Actually, it's only a specific class of machines: the PCX (that's most
of the 715,725 series) that are fully incoherent.  PCXL hack around this
by making the page uncacheable and the 64 bit machines have coherence
index handling which fixes this up (mostly).

  (actually, the pa8800's have IDE CD's on a cmd640 chip, but that oopses
  on boot for no reason we've tracked yet).
 
 With libata, old IDE or both ? and what does the oops look like ?

Unfortunately, there's no oops; we get a high priority machine check
which means something has gone wrong somewhere and it's not pretty.
It's on my todo list to track down ... I just don't have one of these
boxes and CDs are hard to play with remotely.

James


-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-12 Thread Alan Cox
 Has anyone else reported a problem like this?  It requires
 non-coherent DMA, and a lack of a cache invalidate instruction, and
 one of the drivers that has this problem (it looks like sata_qstor
 does too, I haven't looked at others), so maybe that doesn't cover
 any other architectures.

Nobody has, not even PA-RISC which is normally guaranteed to make life
miserable in the caching area but I agree entirely with your diagnosis
and that buffer should indeed be marked cache aligned

 I can provide a patch if you're interested.

Please do.

Alan
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: libata/sata_sil24 cache alignment problem?

2008-02-12 Thread Thomas Evans
I wonder if this may be what I am seeing with the Si3124 on my Alpha 
based setup.


I'm not sure if Alpha meets all the criteria, but the thing refuses to 
recognize any drivers when they are connected and I see what are 
supposed pci parity failures.


maybe not ...

...tom


Mark Mason wrote:

Hi All,

I've implemented the Linux PCI support for a new architecture, and
have run into what appears to be a bug in libata, but I don't
understand why it wouldn't have been seen on other architectures.

The processor is a Tile64, which is a 64 core, 64 bit VLIW processor
with non-coherent DMA - DMA transfers bypass the cache, so cache
coherence must be maintained manually.

I am working with libata v2.0, from Linux 2.6.18, and the sata_sil24
driver for a Silicon Images SIL3531A chip.

The problem occurs when the drive's model and serial numbers are read
at startup via ata_dev_read_id().  They are read once on driver
startup, then when the the error handler first runs it verifies that
the model and serial numbers match what was read when the driver
started.

The problem is with the proximity of the private_data and sector_buf
members of the ata_port struct, and the sector_buf not being cache
aligned.  ata_qc_issue() calls dma_map_single(), which in my case
flushes and invalidates the cache for the buffer it's about DMA into
(ata_port-sector_buf), then calls sil24_qc_issue().

sil24_qc_issue() then dereferences ata_port-private_data, which
causes the cache line containing it to be read in, bringing part of
the sector_buf with it, before the DMA transfer has taken place.  The
Tile64 processor does not have a cache invalidate instruction, only a
flush/invalidate, so dma_unmap_single() can't invalidate the portion
of the sector_buf that's been inadvertently read in, and I get a
serial number and/or model number mismatch, due to part of the buffer
being stale.

Documentation/DMA-API.txt states that addresses passed to
dma_map_single() and dma_unmap_single() must be cache aligned for this
reason.  Both calls to ata_dev_read_id() request DMA into a non
cache-aligned buffer, but only the second call - via
ata_dev_same_device() - has a conflict that can cause the cache line
to be read back in during the very narrow window for which this
vulnerability exists.

Has anyone else reported a problem like this?  It requires
non-coherent DMA, and a lack of a cache invalidate instruction, and
one of the drivers that has this problem (it looks like sata_qstor
does too, I haven't looked at others), so maybe that doesn't cover
any other architectures.

I can provide a patch if you're interested.
-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
  

-
To unsubscribe from this list: send the line unsubscribe linux-ide in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html