send ATA commands

1,392 views
Skip to first unread message

Jonathan Pittman

unread,
Apr 29, 2012, 4:16:57 PM4/29/12
to golang-nuts
Does anyone have any examples or suggestions for how to send ATA commands to a drive?

Jiří Zárevúcky

unread,
Apr 29, 2012, 6:04:13 PM4/29/12
to golan...@googlegroups.com
That sounds like something only the operating system has access to. Are you sure you're asking the right group?

Jonathan Pittman

unread,
Apr 29, 2012, 10:33:33 PM4/29/12
to Jiří Zárevúcky, golan...@googlegroups.com, golan...@googlegroups.com
Software can be written to do this.  I have seen it done in C/C++.  I just want to get an idea of how to do it with Go.  I figure it requires the syscall package, which I am not deeply familiar or comfortable with yet.  Will add golang-dev to see if anyone on that list has insight.

si guy

unread,
Apr 30, 2012, 4:53:16 AM4/30/12
to golan...@googlegroups.com
If you already have the c to do it, you can import it with cgo, the same goes for c++ using swig.

Aram Hăvărneanu

unread,
Apr 30, 2012, 8:55:44 AM4/30/12
to Jonathan Pittman, Jiří Zárevúcky, golan...@googlegroups.com, golan...@googlegroups.com
Linuxes these days emulate a sd(4) SCSI device for every storage
device, regardless of the type of the device. If you want to speak ATA
with your device, there's a libATA library on top on sd(4).
Unfortunately if you want to use libATA, you need to use cgo. If you
only want to do a simple thing, libATA is in itself a trivial layer,
so you can wrap your thing in SCSI commands easily.

Before this nonsense we have today, you could just do ioctl(2) with
IOCTL_ATA_PASS_THROUGH_DIRECT. This is easy to do from Go, and I
imagine it should still work. Check linux/include/linux/hdreg.h.

What exactly are you trying to do? Not that SCSI is in any way better
than ATA, but it's much simpler to use than ATA in Linux nowadays,
can't you use SCSI instead?

--
Aram Hăvărneanu

Aram Hăvărneanu

unread,
Apr 30, 2012, 9:03:37 AM4/30/12
to Jiří Zárevúcky, golan...@googlegroups.com
Jiří Zárevúcky
> That sounds like something only the operating system has access to.

Not really. Every mainsteam operating system exposes in the namespace
devices that talk SCSI. For example it is the only way you can write
CDs. ATA used to be this way too, and in some circles it still is.

--
Aram Hăvărneanu

Russ Cox

unread,
Apr 30, 2012, 11:56:12 PM4/30/12
to Jonathan Pittman, golang-nuts
That's going to be very OS-specific, but it's certainly doable.
This should work on Plan 9 (untested):

package main

import (
"bytes"
"log"
"os"
)

func main() {
log.SetFlags(0)
if len(os.Args) != 1+1 {
log.Fatal("usage: eject /dev/sdD0")
}

f, err := os.OpenFile(os.Args[1]+"/raw", os.O_RDWR, 0)
if err != nil {
log.Fatal(err)
}
scsicmd([]byte{0x1b, 0, 0, 0, 2, 0}, []byte{})
}

func scsicmd(cmd, data []byte) {
if n, err := f.Write(cmd); n != len(cmd) || err != nil {
log.Fatalf("write: %v", err)
}
if n, err := f.Write(data); n != len(data) || err != nil {
log.Fatal("write: %v", err)
}

resp := make([]byte, 16)
n, err := f.Read(resp)
if err != nil {
log.Fatal("read response: %v", err)
}
if !bytes.Equal(resp[:n], []byte("0")) {
log.Fatal("error %v", string(resp[:n]))
}
}

Jonathan Pittman

unread,
May 1, 2012, 10:56:57 AM5/1/12
to r...@golang.org, golang-nuts
Thanks for the example Russ.  For more info to the thread...

The OS would be linux.  The initial commands I need to perform are:

IDENTIFY DEVICE (0xEC)
FLUSH CACHE (0xE7)

...but others would follow soon after.  I would like to see an example of using syscall and ioctl on linux to communicate with a drive.  If there are better ways, I am open to suggestions.  Using cgo or swig are options, but would prefer a pure Go solution.

Devon H. O'Dell

unread,
May 1, 2012, 11:01:11 AM5/1/12
to Jonathan Pittman, r...@golang.org, golang-nuts
This paste from the list from forever ago about termios illustrates
using the syscall.Syscall function to call a syscall that has not been
exported (such as ioctl(2), which is what this uses to do terminal
stuff).

http://go.pastie.org/813153

--dho

Op 1 mei 2012 10:56 heeft Jonathan Pittman
<jonathan.m...@gmail.com> het volgende geschreven:

Russ Cox

unread,
May 1, 2012, 10:22:07 PM5/1/12
to Jonathan Pittman, golang-nuts
On Tue, May 1, 2012 at 10:56 AM, Jonathan Pittman
<jonathan.m...@gmail.com> wrote:
> Thanks for the example Russ.  For more info to the thread...
>
> The OS would be linux.  The initial commands I need to perform are:
>
> IDENTIFY DEVICE (0xEC)
> FLUSH CACHE (0xE7)
>
> ...but others would follow soon after.  I would like to see an example of
> using syscall and ioctl on linux to communicate with a drive.  If there are
> better ways, I am open to suggestions.  Using cgo or swig are options, but
> would prefer a pure Go solution.

I think what you really need is to find out how to do this in C (the
actual system calls, not some library). Once you know that, writing
it in Go instead of C is very easy. I believe that if you search for
[ioctl HDIO_DRIVE_CMD] that should lead you in the right direction.

Russ

Jonathan Pittman

unread,
Jul 28, 2012, 4:12:49 PM7/28/12
to r...@golang.org, golang-nuts
FWIW, I recently picked this back up after having other things on my plate.

Russ was totally right about figuring out how to do it in C and then write it in Go.  It is proving to be an interesting learning experience, but it is also proving to be rather simple once you get the hang of it.  There is not much to it.  I did translate some of the structs and constants from /usr/include/linux/hdreg.h into Go with the help of cgo -godefs.  The little I have done so far (read smart values and get identity) have been smooth in native Go.  No C required.
Reply all
Reply to author
Forward
0 new messages