Beginner's guide to writing a SATA device driver?

Ozgur Karatas ozgurk at ieee.org
Sun May 8 08:08:55 EDT 2022


On Sun, May 8, 2022 at 4:51 AM Gabriel L. Somlo <gsomlo at gmail.com> wrote:
>
> Hi Ozgur,
>

Hello Gabriel,

> (replying off-list so as not to discourage further answers, on the off
> chance I'm wrong about what I'm going to say next... :)

I don't think that was a good method, because why? Please let me explain.

Linux kernel development is carried out by e-mail from the very first moment,
and Kernelnewbies exist to reduce high traffic on kernel development
list but to discuss new starters (newbie).

And no matter how wrong you are or if you are misinformed here, we
have ample time to discuss it :)
And dont worry to send email to mailing lists when its related to Linux kernel.

The biggest reason why Linux is progressing in modern way: today is
that it takes an interest in all ideas via e-mail and handles new
starters with a tool as simple as mail. Also when you share with
peoples, better and more knowledgeable peoples will share better
information with you. :)

There are very good high-level kernel developers who follow our
Kernelnewbies lists and for these kernel developers social media is
already these mailing lists and they start with a lot of e-mails
daily. For example Greg-KH one of Linux maintainers and usually
answers here as well. However, if isnt enough for you and you are
interested in kernel level development and you have question? its okay
to send an e-mail even to Linus Torvalds, because he will reply to you
as soon as he is interested topic :)

Another thing, I'm the most ignorant person here :) I try to help new
peoples very quickly both to learn and to help and when you use lists,
you will reach much better peoples. Kernelnewbies is first place to
interact with kernel development and feel free to use their mailing
lists everytime :)

> First off, thanks for the links. I found both `ata_generic.c` and
> `sata_mv.c` under `drivers/ata/` in the linux source tree. The first
> one is "too abstract" (i.e., nothing about where the DMA registers of
> the "hardware" are, and how the sg lists are "connected" to them).
>

In Linux kernel, hardware and interrupt is not addressed in driver C
code. I would suggest that you get some idea about Linux Subsystem and
would like you to take a quick read and take a look at Linux Device
Drivers book. I think this give fgor you some insight into the
conceptual architecture of Linux Kernel.

Please take a look:

* Kernel Inter-process communication

> The second one (marvell) is a bit of a "firehose" in and of itself... :)
>
> I was already mostly familiar with how to pass configuration into
> drivers via devicetree.
>
> The thing that was eye opening, I think, was the recap of block
> devices in the "essential linux device drivers" book.

I suggest you take a look at IRQ, Interrupt and handler in Linux kernel.

https://www.kernel.org/doc/html/latest/core-api/index.html#low-level-hardware-management

>
> It made me realize that ultimately there's nothing SATA about the
> software/register interface of my device -- while it might use SATA
> internally and when connecting to the actual hdd/media, it
> encapsulates it completely: the software/register interface only
> exposes a 1-bit "on/off" switch for the phy (with a 4-bit status
> readout), and generic DMA block transfer interfaces, one per (r/w)
> direction.
>
> There's *nothing* allowing the software to query the actual hard drive
> geometry, capacity, or any other parameters. There's also no way to
> send "commands" back and forth through this interface. Only data
> blocks to/from specific sector numbers -- that's *it*!
>

As i mentioned before, Linux kernel driver code dont deal with
hardware recognition and addressing. Basicly, driver these requests
are forwarded t kernel and which kernel handles and request and
response.

If i'm wrong about this, other peoples will give better information
immediately (importance of mailing-lists :) )

> This is probably why I was experiencing such extreme levels of
> cognitive dissonance while trying to "fit" this thing within the SATA
> driver framework, and nothing in there made any sense w.r.t. it... :)
>
> I'll try to get confirmation of this with the developer of the
> LiteSATA fpga IP block, to be 100% sure I'm understanding this
> correctly.

in my opinion, manufacturers usually handle SATA disk (block layer)
and driver work on Linux kernel side however, you can still access
them all so LKML mailing lists are heavily trafficked (if you are sure
it would be more accurate to just send a patch) but you can still ask
questions to people there.

List: linux-ide at vger.kernel.org

> Thanks for getting me unstuck! :)
>
> Cheers,

You are welcome and thanks for use kernelnewbies.

Regards,

> --Gabriel
>
> On Sun, May 08, 2022 at 02:40:11AM +0400, Ozgur Karatas wrote:
> > On Sun, May 8, 2022 at 12:34 AM Gabriel L. Somlo <gsomlo at gmail.com> wrote:
> > >
> > > Hi,
> > >
> >
> > Hello Gabriel,
> >
> > > I have a (soft-IP, FPGA based, single-port) very simple SATA device
> > > (https://github.com/enjoy-digital/litesata) that provides me (r/w)
> > > access to a single physical SATA hard drive. I can access one sector
> > > at a time from bare-metal C code, using DMA and the following three
> > > MMIO register sets:
> > >
> > >         - phy:
> > >                 u8 enable;      // write 1 to bit 0 to enable phy
> > >                                 // bits 1..7 reserved
> > >                 u8 status_ro ;  // bit 0 = 1 if overall phy ready
> > >                                 // bit 1 = 1 if phy tx ready
> > >                                 // bit 2 = 1 if phy rx ready
> > >                                 // bit 3 = 1 if phy ctrl ready
> > >
> > >         - dma_writer:           // write one 512-bit sector to disk
> > >                 u64 sector;     // 48-bit disk sector number
> > >                 u64 base;       // 64-bit dma base address (source buffer)
> > >                 u8  start;      // write 1 to bit 0 to start DMA transfer
> > >                 u8  done_ro;    // read 1 from bit 0 when transfer complete
> > >                 u8  error_ro;   // read 1 from bit 0 if transfer failed
> > >
> > >         - dma_reader:           // read one 512-bit sector from disk
> > >                 u64 sector;     // 48-bit disk sector number
> > >                 u64 base;       // 64-bit dma base address (dest. buffer)
> > >                 u8  start;      // write 1 to bit 0 to start DMA transfer
> > >                 u8  done_ro;    // read 1 from bit 0 when transfer complete
> > >                 u8  error_ro;   // read 1 from bit 0 if transfer failed
> > >
> > > For practice, I'm trying to write a low level SATA driver to access
> > > the hard drive from Linux using this device.
> > >
> > > I've tried studying existing drivers under `drivers/ata/*` to get an
> > > idea how to "connect" my device into the Linux SATA subsystem, and
> > > also tried studying the "libATA Developer’s Guide" at
> > > https://www.kernel.org/doc/html/v5.18-rc5/driver-api/libata.html
> > >
> > > It turns out there's a sizable "impedance mismatch" between my
> > > understanding of my device's simple register interface and most of
> > > the "production" devices for which existing drivers have been
> > > written in `drivers/ata/*`...
> > >
> > > I'm not even sure if I should be looking at `drivers/ata/ahci_*.c` or
> > > rather `drivers/ata/sata_*.c` :)
> > >
> > > I'd like some help finding an existing driver that's "closest"
> > > conceptually to the behavior of my device (outlined above), that I can
> > > use as a source of inspiration and as a starting point in learning about
> > > the linux SATA subsystem.
> > >
> >
> > I think, first of all look at how the drivers on SATA hardware are
> > coded under Linux kernel at low level
> > (you are expected to know a little about Linux C standards).
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/ata/
> >
> > and if it were me, I would start with ata_generic.c first:
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/ata/ata_generic.c
> >
> > For another example, you can take a look at Bootlin source code:
> >
> > https://elixir.bootlin.com/linux/latest/source/drivers/ata/sata_mv.c
> >
> > For a working logic, take a look at this document:
> >
> > https://github.com/digi-embedded/linux/blob/v4.1/dey-2.2/maint/Documentation/devicetree/bindings/ata/ahci-platform.txt
> >
> > Right after these, you should have an idea about "Block Drivers"
> > because you will need to contact kernel.
> > Here is a great guide for you:
> >
> > http://www.embeddedlinux.org.cn/essentiallinuxdevicedrivers/final/ch14.html
> >
> > I think all these will be enough for you at first.
> >
> > Salut,
> >
> > Ozgur
> >
> > > Alternatively, is there some "guided tour to the Linux SATA subsystem"
> > > that's a bit less of a firehose than the "LibATA Developer's Guide"?
> > >
> > > Many thanks for any clues or pointers,
> > > --Gabriel



More information about the Kernelnewbies mailing list