missing files

This commit is contained in:
Olaf Rempel 2010-06-12 13:43:51 +02:00
parent f99924d77f
commit 1c13dd3f58
3 changed files with 874 additions and 0 deletions

152
plugins/diskstandby.c Normal file
View File

@ -0,0 +1,152 @@
/***************************************************************************
* Copyright (C) 06/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "configfile.h"
#include "logging.h"
#include "plugins.h"
#include "probe.h"
#include "sgio.h"
int verbose = 0;
int prefer_ata12 = 0;
struct sammler_plugin plugin;
struct device_entry {
struct list_head list;
char *devpath;
};
static LIST_HEAD(device_list);
static const char *ds_def = {
"DS:active:GAUGE:90:0:1 "
};
static const char * get_ds(int ds_id)
{
return ds_def;
}
static int probe(void)
{
struct device_entry *entry;
list_for_each_entry(entry, &device_list, list) {
int fd = open(entry->devpath, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
log_print(LOG_ERROR, "%s: failed to open %s", plugin.name, entry->devpath);
continue;
}
uint8_t args[4] = { ATA_OP_CHECKPOWERMODE1, 0, 0, 0 };
if (do_drive_cmd(fd, args)) {
args[0] = ATA_OP_CHECKPOWERMODE2;
if (do_drive_cmd(fd, args)) {
log_print(LOG_ERROR, "%s: failed to query %s", plugin.name, entry->devpath);
close(fd);
continue;
}
}
/*
switch (args[2]) {
case 0x00: state = "standby"; break;
case 0x40: state = "NVcache_spindown"; break;
case 0x41: state = "NVcache_spinup"; break;
case 0x80: state = "idle"; break;
case 0xff: state = "active/idle"; break;
default: state = "unknown"; break;
}
*/
char *dev = strrchr(entry->devpath, '/');
if (dev == NULL) {
dev = entry->devpath;
} else {
dev++;
}
char filename[32];
int len = snprintf(filename, sizeof(filename), "diskstandby-%s.rrd", dev);
if (len < 0 || len >= sizeof(filename))
continue;
probe_submit(&plugin, filename, 0, "%u", (args[2] == 0xff) ? 1 : 0);
close(fd);
}
return 0;
}
static int init_cb(struct strtoken *tokens, void *privdata)
{
if (tokens->count != 1) {
log_print(LOG_ERROR, "%s: parse error", plugin.name);
return -1;
}
struct device_entry *entry = malloc(sizeof(struct device_entry));
if (entry == NULL) {
log_print(LOG_ERROR, "%s: out of memory", plugin.name);
return -1;
}
entry->devpath = strdup(tokens->field[0]);
log_print(LOG_INFO, "%s: added server '%s'", plugin.name, entry->devpath);
list_add_tail(&entry->list, &device_list);
return 0;
}
static int init(void)
{
config_get_strtokens("p_diskstandby", "device", ",", 1, init_cb, NULL);
return 0;
}
static int fini(void)
{
struct device_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &device_list, list) {
free(entry->devpath);
free(entry);
}
return 0;
}
struct sammler_plugin plugin = {
.name = "diskstandby",
.interval = 60,
.init = &init,
.fini = &fini,
.probe = &probe,
.get_ds = &get_ds,
};

492
plugins/sgio.c Normal file
View File

@ -0,0 +1,492 @@
/* sgio.c - by Mark Lord (C) 2007 -- freely distributable */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include "sgio.h"
//#include "hdparm.h"
#include <linux/hdreg.h>
extern int verbose;
extern int prefer_ata12;
/*
* Taskfile layout for SG_ATA_16 cdb:
*
* LBA48:
* cdb[ 3] = hob_feat
* cdb[ 5] = hob_nsect
* cdb[ 7] = hob_lbal
* cdb[ 9] = hob_lbam
* cdb[11] = hob_lbah
*
* LBA28/LBA48:
* cdb[ 4] = feat
* cdb[ 6] = nsect
* cdb[ 8] = lbal
* cdb[10] = lbam
* cdb[12] = lbah
* cdb[13] = device
* cdb[14] = command
*
* Taskfile layout for SG_ATA_12 cdb:
*
* cdb[ 3] = feat
* cdb[ 4] = nsect
* cdb[ 5] = lbal
* cdb[ 6] = lbam
* cdb[ 7] = lbah
* cdb[ 8] = device
* cdb[ 9] = command
*
* dxfer_direction choices:
* SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV, SG_DXFER_NONE
*/
static inline int needs_lba48 (__u8 ata_op, __u64 lba, unsigned int nsect)
{
const __u64 lba28_limit = (1<<28) - 1;
switch (ata_op) {
case ATA_OP_READ_PIO_EXT:
case ATA_OP_READ_DMA_EXT:
case ATA_OP_WRITE_PIO_EXT:
case ATA_OP_WRITE_DMA_EXT:
case ATA_OP_READ_VERIFY_EXT:
case ATA_OP_WRITE_UNC_EXT:
case ATA_OP_READ_NATIVE_MAX_EXT:
case ATA_OP_SET_MAX_EXT:
case ATA_OP_FLUSHCACHE_EXT:
return 1;
}
if (lba >= lba28_limit)
return 1;
if (nsect) {
if (nsect > 0xff)
return 1;
if ((lba + nsect - 1) >= lba28_limit)
return 1;
}
return 0;
}
void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect)
{
memset(tf, 0, sizeof(*tf));
tf->command = ata_op;
tf->dev = ATA_USING_LBA;
tf->lob.lbal = lba;
tf->lob.lbam = lba >> 8;
tf->lob.lbah = lba >> 16;
tf->lob.nsect = nsect;
if (needs_lba48(ata_op, lba, nsect)) {
tf->is_lba48 = 1;
tf->hob.nsect = nsect >> 8;
tf->hob.lbal = lba >> 24;
tf->hob.lbam = lba >> 32;
tf->hob.lbah = lba >> 40;
} else {
tf->dev |= (lba >> 24) & 0x0f;
}
}
#ifdef SG_IO
__u64 tf_to_lba (struct ata_tf *tf)
{
__u32 lba24, lbah;
__u64 lba64;
lba24 = (tf->lob.lbah << 16) | (tf->lob.lbam << 8) | (tf->lob.lbal);
if (tf->is_lba48)
lbah = (tf->hob.lbah << 16) | (tf->hob.lbam << 8) | (tf->hob.lbal);
else
lbah = (tf->dev & 0x0f);
lba64 = (((__u64)lbah) << 24) | (__u64)lba24;
return lba64;
}
enum {
SG_CDB2_TLEN_NODATA = 0 << 0,
SG_CDB2_TLEN_FEAT = 1 << 0,
SG_CDB2_TLEN_NSECT = 2 << 0,
SG_CDB2_TLEN_BYTES = 0 << 2,
SG_CDB2_TLEN_SECTORS = 1 << 2,
SG_CDB2_TDIR_TO_DEV = 0 << 3,
SG_CDB2_TDIR_FROM_DEV = 1 << 3,
SG_CDB2_CHECK_COND = 1 << 5,
};
static void dump_bytes (const char *prefix, unsigned char *p, int len)
{
int i;
if (prefix)
fprintf(stderr, "%s: ", prefix);
for (i = 0; i < len; ++i)
fprintf(stderr, " %02x", p[i]);
fprintf(stderr, "\n");
}
int sg16 (int fd, int rw, int dma, struct ata_tf *tf,
void *data, unsigned int data_bytes, unsigned int timeout_secs)
{
unsigned char cdb[SG_ATA_16_LEN];
unsigned char sb[32], *desc;
struct scsi_sg_io_hdr io_hdr;
memset(&cdb, 0, sizeof(cdb));
memset(&sb, 0, sizeof(sb));
memset(&io_hdr, 0, sizeof(struct scsi_sg_io_hdr));
if (dma) {
//cdb[1] = data ? (rw ? SG_ATA_PROTO_UDMA_OUT : SG_ATA_PROTO_UDMA_IN) : SG_ATA_PROTO_NON_DATA;
cdb[1] = data ? SG_ATA_PROTO_DMA : SG_ATA_PROTO_NON_DATA;
} else {
cdb[1] = data ? (rw ? SG_ATA_PROTO_PIO_OUT : SG_ATA_PROTO_PIO_IN) : SG_ATA_PROTO_NON_DATA;
}
cdb[ 2] = SG_CDB2_CHECK_COND;
if (data) {
cdb[2] |= SG_CDB2_TLEN_NSECT | SG_CDB2_TLEN_SECTORS;
cdb[2] |= rw ? SG_CDB2_TDIR_TO_DEV : SG_CDB2_TDIR_FROM_DEV;
}
if (!prefer_ata12 || tf->is_lba48) {
cdb[ 0] = SG_ATA_16;
cdb[ 4] = tf->lob.feat;
cdb[ 6] = tf->lob.nsect;
cdb[ 8] = tf->lob.lbal;
cdb[10] = tf->lob.lbam;
cdb[12] = tf->lob.lbah;
cdb[13] = tf->dev;
cdb[14] = tf->command;
if (tf->is_lba48) {
cdb[ 1] |= SG_ATA_LBA48;
cdb[ 3] = tf->hob.feat;
cdb[ 5] = tf->hob.nsect;
cdb[ 7] = tf->hob.lbal;
cdb[ 9] = tf->hob.lbam;
cdb[11] = tf->hob.lbah;
}
io_hdr.cmd_len = SG_ATA_16_LEN;
} else {
cdb[ 0] = SG_ATA_12;
cdb[ 3] = tf->lob.feat;
cdb[ 4] = tf->lob.nsect;
cdb[ 5] = tf->lob.lbal;
cdb[ 6] = tf->lob.lbam;
cdb[ 7] = tf->lob.lbah;
cdb[ 8] = tf->dev;
cdb[ 9] = tf->command;
io_hdr.cmd_len = SG_ATA_12_LEN;
}
io_hdr.interface_id = 'S';
io_hdr.mx_sb_len = sizeof(sb);
io_hdr.dxfer_direction = data ? (rw ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV) : SG_DXFER_NONE;
io_hdr.dxfer_len = data ? data_bytes : 0;
io_hdr.dxferp = data;
io_hdr.cmdp = cdb;
io_hdr.sbp = sb;
io_hdr.pack_id = tf_to_lba(tf);
io_hdr.timeout = (timeout_secs ? timeout_secs : 5) * 1000; /* msecs */
if (verbose)
dump_bytes("outgoing cdb", cdb, sizeof(cdb));
if (ioctl(fd, SG_IO, &io_hdr) == -1) {
if (verbose)
perror("ioctl(fd,SG_IO)");
return -1; /* SG_IO not supported */
}
if (verbose)
fprintf(stderr, "SG_IO: ATA_%u status=0x%x, host_status=0x%x, driver_status=0x%x\n",
io_hdr.cmd_len, io_hdr.status, io_hdr.host_status, io_hdr.driver_status);
if (io_hdr.host_status || io_hdr.driver_status != SG_DRIVER_SENSE
|| (io_hdr.status && io_hdr.status != SG_CHECK_CONDITION))
{
if (verbose)
fprintf(stderr, "SG_IO: bad response (not CHECK_CONDITION)\n");
errno = EBADE;
return -1;
}
desc = sb + 8;
if (sb[0] != 0x72 || sb[7] < 14 || desc[0] != 0x09 || desc[1] < 0x0c) {
if (verbose)
dump_bytes("SG_IO: bad/missing sense data, sb[]", sb, sizeof(sb));
errno = EBADE;
return -1;
}
if (verbose)
dump_bytes("SG_IO: sb[]", sb, sizeof(sb));
if (verbose) {
int len = desc[1], maxlen = sizeof(sb) - 8 - 2;
if (len > maxlen)
len = maxlen;
dump_bytes("SG_IO: desc[]", desc, len);
}
tf->is_lba48 = desc[ 2] & 1;
tf->error = desc[ 3];
tf->lob.nsect = desc[ 5];
tf->lob.lbal = desc[ 7];
tf->lob.lbam = desc[ 9];
tf->lob.lbah = desc[11];
tf->dev = desc[12];
tf->status = desc[13];
tf->hob.feat = 0;
if (tf->is_lba48) {
tf->hob.nsect = desc[ 4];
tf->hob.lbal = desc[ 6];
tf->hob.lbam = desc[ 8];
tf->hob.lbah = desc[10];
} else {
tf->hob.nsect = 0;
tf->hob.lbal = 0;
tf->hob.lbam = 0;
tf->hob.lbah = 0;
}
if (verbose)
fprintf(stderr, " ATA_%u stat=%02x err=%02x nsect=%02x lbal=%02x lbam=%02x lbah=%02x dev=%02x\n",
io_hdr.cmd_len, tf->status, tf->error, tf->lob.nsect, tf->lob.lbal, tf->lob.lbam, tf->lob.lbah, tf->dev);
if (tf->status & (ATA_STAT_ERR | ATA_STAT_DRQ)) {
if (verbose) {
fprintf(stderr, "I/O error, ata_op=0x%02x ata_status=0x%02x ata_error=0x%02x\n",
tf->command, tf->status, tf->error);
}
errno = EIO;
return -1;
}
return 0;
}
#endif /* SG_IO */
int do_drive_cmd (int fd, unsigned char *args)
{
#ifdef SG_IO
struct ata_tf tf;
void *data = NULL;
unsigned int data_bytes = 0;
int rc;
if (args == NULL)
goto use_legacy_ioctl;
/*
* Reformat and try to issue via SG_IO:
*/
if (args[3]) {
data_bytes = args[3] * 512;
data = args + 4;
}
tf_init(&tf, args[0], 0, args[1]);
tf.lob.feat = args[2];
if (tf.command == ATA_OP_SMART) {
tf.lob.nsect = args[3];
tf.lob.lbal = args[1];
tf.lob.lbam = 0x4f;
tf.lob.lbah = 0xc2;
}
rc = sg16(fd, SG_READ, SG_PIO, &tf, data, data_bytes, 0);
if (rc == -1) {
if (errno == EINVAL || errno == ENODEV)
goto use_legacy_ioctl;
}
if (rc == 0 || errno == EIO) {
args[0] = tf.status;
args[1] = tf.error;
args[2] = tf.lob.nsect;
}
return rc;
use_legacy_ioctl:
#endif /* SG_IO */
if (verbose)
fprintf(stderr, "Trying legacy HDIO_DRIVE_CMD\n");
return ioctl(fd, HDIO_DRIVE_CMD, args);
}
int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs)
{
int rc;
#ifdef SG_IO
struct ata_tf tf;
void *data = NULL;
unsigned int data_bytes = 0;
int rw = SG_READ;
/*
* Reformat and try to issue via SG_IO:
*/
tf_init(&tf, 0, 0, 0);
#if 1 /* debugging */
if (verbose) {
printf("oflags.lob_all=0x%02x, flags={", r->oflags.lob_all);
if (r->oflags.lob.feat) printf(" feat");
if (r->oflags.lob.lbal) printf(" lbal");
if (r->oflags.lob.nsect)printf(" nsect");
if (r->oflags.lob.lbam) printf(" lbam");
if (r->oflags.lob.lbah) printf(" lbah");
if (r->oflags.lob.dev) printf(" dev");
if (r->oflags.lob.command) printf(" command");
printf(" }\n");
printf("oflags.hob_all=0x%02x, flags={", r->oflags.hob_all);
if (r->oflags.hob.feat) printf(" feat");
if (r->oflags.hob.lbal) printf(" lbal");
if (r->oflags.hob.nsect)printf(" nsect");
if (r->oflags.hob.lbam) printf(" lbam");
if (r->oflags.hob.lbah) printf(" lbah");
printf(" }\n");
}
#endif
if (r->oflags.lob.feat) tf.lob.feat = r->lob.feat;
if (r->oflags.lob.lbal) tf.lob.lbal = r->lob.lbal;
if (r->oflags.lob.nsect) tf.lob.nsect = r->lob.nsect;
if (r->oflags.lob.lbam) tf.lob.lbam = r->lob.lbam;
if (r->oflags.lob.lbah) tf.lob.lbah = r->lob.lbah;
if (r->oflags.lob.dev) tf.dev = r->lob.dev;
if (r->oflags.lob.command) tf.command = r->lob.command;
if (r->oflags.hob_all || r->iflags.hob_all) {
tf.is_lba48 = 1;
if (r->oflags.hob.feat) tf.hob.feat = r->hob.feat;
if (r->oflags.hob.lbal) tf.hob.lbal = r->hob.lbal;
if (r->oflags.hob.nsect)tf.hob.nsect = r->hob.nsect;
if (r->oflags.hob.lbam) tf.hob.lbam = r->hob.lbam;
if (r->oflags.hob.lbah) tf.hob.lbah = r->hob.lbah;
if (verbose)
fprintf(stderr, "using LBA48 taskfile\n");
}
switch (r->cmd_req) {
case TASKFILE_CMD_REQ_OUT:
case TASKFILE_CMD_REQ_RAW_OUT:
data_bytes = r->obytes;
data = r->data;
rw = SG_WRITE;
break;
case TASKFILE_CMD_REQ_IN:
data_bytes = r->ibytes;
data = r->data;
break;
}
rc = sg16(fd, rw, SG_PIO, &tf, data, data_bytes, timeout_secs);
if (rc == -1) {
if (errno == EINVAL || errno == ENODEV)
goto use_legacy_ioctl;
}
if (rc == 0 || errno == EIO) {
if (r->iflags.lob.feat) r->lob.feat = tf.error;
if (r->iflags.lob.lbal) r->lob.lbal = tf.lob.lbal;
if (r->iflags.lob.nsect) r->lob.nsect = tf.lob.nsect;
if (r->iflags.lob.lbam) r->lob.lbam = tf.lob.lbam;
if (r->iflags.lob.lbah) r->lob.lbah = tf.lob.lbah;
if (r->iflags.lob.dev) r->lob.dev = tf.dev;
if (r->iflags.lob.command) r->lob.command = tf.status;
if (r->iflags.hob.feat) r->hob.feat = tf.hob.feat;
if (r->iflags.hob.lbal) r->hob.lbal = tf.hob.lbal;
if (r->iflags.hob.nsect) r->hob.nsect = tf.hob.nsect;
if (r->iflags.hob.lbam) r->hob.lbam = tf.hob.lbam;
if (r->iflags.hob.lbah) r->hob.lbah = tf.hob.lbah;
}
return rc;
use_legacy_ioctl:
#else
timeout_secs = 0; /* keep compiler happy */
#endif /* SG_IO */
if (verbose)
fprintf(stderr, "trying legacy HDIO_DRIVE_TASKFILE\n");
errno = 0;
rc = ioctl(fd, HDIO_DRIVE_TASKFILE, r);
if (verbose) {
int err = errno;
fprintf(stderr, "rc=%d, errno=%d, returned ATA registers: ", rc, err);
if (r->iflags.lob.feat) fprintf(stderr, " er=%02x", r->lob.feat);
if (r->iflags.lob.nsect) fprintf(stderr, " ns=%02x", r->lob.nsect);
if (r->iflags.lob.lbal) fprintf(stderr, " ll=%02x", r->lob.lbal);
if (r->iflags.lob.lbam) fprintf(stderr, " lm=%02x", r->lob.lbam);
if (r->iflags.lob.lbah) fprintf(stderr, " lh=%02x", r->lob.lbah);
if (r->iflags.lob.dev) fprintf(stderr, " dh=%02x", r->lob.dev);
if (r->iflags.lob.command) fprintf(stderr, " st=%02x", r->lob.command);
if (r->iflags.hob.feat) fprintf(stderr, " err=%02x", r->hob.feat);
if (r->iflags.hob.nsect) fprintf(stderr, " err=%02x", r->hob.nsect);
if (r->iflags.hob.lbal) fprintf(stderr, " err=%02x", r->hob.lbal);
if (r->iflags.hob.lbam) fprintf(stderr, " err=%02x", r->hob.lbam);
if (r->iflags.hob.lbah) fprintf(stderr, " err=%02x", r->hob.lbah);
fprintf(stderr, "\n");
errno = err;
}
if (rc == -1 && errno == EINVAL) {
fprintf(stderr, "The running kernel lacks CONFIG_IDE_TASK_IOCTL support for this device.\n");
errno = EINVAL;
}
return rc;
}
void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48,
__u64 lba, unsigned int nsect, int data_bytes)
{
memset(r, 0, sizeof(struct hdio_taskfile) + data_bytes);
if (!data_bytes) {
r->dphase = TASKFILE_DPHASE_NONE;
r->cmd_req = TASKFILE_CMD_REQ_NODATA;
} else if (rw == RW_WRITE) {
r->dphase = TASKFILE_DPHASE_PIO_OUT;
r->cmd_req = TASKFILE_CMD_REQ_RAW_OUT;
r->obytes = data_bytes;
} else { /* rw == RW_READ */
r->dphase = TASKFILE_DPHASE_PIO_IN;
r->cmd_req = TASKFILE_CMD_REQ_IN;
r->ibytes = data_bytes;
}
r->lob.command = ata_op;
r->oflags.lob.command = 1;
r->oflags.lob.dev = 1;
r->oflags.lob.lbal = 1;
r->oflags.lob.lbam = 1;
r->oflags.lob.lbah = 1;
r->oflags.lob.nsect = 1;
r->iflags.lob.command = 1;
r->iflags.lob.feat = 1;
r->lob.nsect = nsect;
r->lob.lbal = lba;
r->lob.lbam = lba >> 8;
r->lob.lbah = lba >> 16;
r->lob.dev = 0xa0 | ATA_USING_LBA;
if (needs_lba48(ata_op, lba, nsect) || force_lba48) {
r->hob.nsect = nsect >> 8;
r->hob.lbal = lba >> 24;
r->hob.lbam = lba >> 32;
r->hob.lbah = lba >> 40;
r->oflags.hob.nsect = 1;
r->oflags.hob.lbal = 1;
r->oflags.hob.lbam = 1;
r->oflags.hob.lbah = 1;
} else {
r->lob.dev |= (lba >> 24) & 0x0f;
}
}

230
plugins/sgio.h Normal file
View File

@ -0,0 +1,230 @@
/* prototypes and stuff for ATA command ioctls */
#include <linux/types.h>
enum {
ATA_OP_READ_PIO = 0x20,
ATA_OP_READ_PIO_ONCE = 0x21,
ATA_OP_READ_LONG = 0x22,
ATA_OP_READ_LONG_ONCE = 0x23,
ATA_OP_READ_PIO_EXT = 0x24,
ATA_OP_READ_DMA_EXT = 0x25,
ATA_OP_READ_FPDMA = 0x60, // NCQ
ATA_OP_WRITE_PIO = 0x30,
ATA_OP_WRITE_LONG = 0x32,
ATA_OP_WRITE_LONG_ONCE = 0x33,
ATA_OP_WRITE_PIO_EXT = 0x34,
ATA_OP_WRITE_DMA_EXT = 0x35,
ATA_OP_WRITE_FPDMA = 0x61, // NCQ
ATA_OP_READ_VERIFY = 0x40,
ATA_OP_READ_VERIFY_ONCE = 0x41,
ATA_OP_READ_VERIFY_EXT = 0x42,
ATA_OP_WRITE_UNC_EXT = 0x45, // lba48, no data, uses feat reg
ATA_OP_FORMAT_TRACK = 0x50,
ATA_OP_DOWNLOAD_MICROCODE = 0x92,
ATA_OP_STANDBYNOW2 = 0x94,
ATA_OP_CHECKPOWERMODE2 = 0x98,
ATA_OP_SLEEPNOW2 = 0x99,
ATA_OP_PIDENTIFY = 0xa1,
ATA_OP_READ_NATIVE_MAX = 0xf8,
ATA_OP_READ_NATIVE_MAX_EXT = 0x27,
ATA_OP_SMART = 0xb0,
ATA_OP_DCO = 0xb1,
ATA_OP_ERASE_SECTORS = 0xc0,
ATA_OP_READ_DMA = 0xc8,
ATA_OP_WRITE_DMA = 0xca,
ATA_OP_DOORLOCK = 0xde,
ATA_OP_DOORUNLOCK = 0xdf,
ATA_OP_STANDBYNOW1 = 0xe0,
ATA_OP_IDLEIMMEDIATE = 0xe1,
ATA_OP_SETIDLE = 0xe3,
ATA_OP_SET_MAX = 0xf9,
ATA_OP_SET_MAX_EXT = 0x37,
ATA_OP_SET_MULTIPLE = 0xc6,
ATA_OP_CHECKPOWERMODE1 = 0xe5,
ATA_OP_SLEEPNOW1 = 0xe6,
ATA_OP_FLUSHCACHE = 0xe7,
ATA_OP_FLUSHCACHE_EXT = 0xea,
ATA_OP_IDENTIFY = 0xec,
ATA_OP_SETFEATURES = 0xef,
ATA_OP_SECURITY_SET_PASS = 0xf1,
ATA_OP_SECURITY_UNLOCK = 0xf2,
ATA_OP_SECURITY_ERASE_PREPARE = 0xf3,
ATA_OP_SECURITY_ERASE_UNIT = 0xf4,
ATA_OP_SECURITY_FREEZE_LOCK = 0xf5,
ATA_OP_SECURITY_DISABLE = 0xf6,
};
/*
* Some useful ATA register bits
*/
enum {
ATA_USING_LBA = (1 << 6),
ATA_STAT_DRQ = (1 << 3),
ATA_STAT_ERR = (1 << 0),
};
/*
* Useful parameters for init_hdio_taskfile():
*/
enum { RW_READ = 0,
RW_WRITE = 1,
LBA28_OK = 0,
LBA48_FORCE = 1,
};
/*
* Definitions and structures for use with SG_IO + ATA_16:
*/
struct ata_lba_regs {
__u8 feat;
__u8 nsect;
__u8 lbal;
__u8 lbam;
__u8 lbah;
};
struct ata_tf {
__u8 dev;
__u8 command;
__u8 error;
__u8 status;
__u8 is_lba48;
struct ata_lba_regs lob;
struct ata_lba_regs hob;
};
/*
* Definitions and structures for use with HDIO_DRIVE_TASKFILE:
*/
enum {
/*
* These (redundantly) specify the category of the request
*/
TASKFILE_CMD_REQ_NODATA = 0, /* ide: IDE_DRIVE_TASK_NO_DATA */
TASKFILE_CMD_REQ_IN = 2, /* ide: IDE_DRIVE_TASK_IN */
TASKFILE_CMD_REQ_OUT = 3, /* ide: IDE_DRIVE_TASK_OUT */
TASKFILE_CMD_REQ_RAW_OUT= 4, /* ide: IDE_DRIVE_TASK_RAW_WRITE */
/*
* These specify the method of transfer (pio, dma, multi, ..)
*/
TASKFILE_DPHASE_NONE = 0, /* ide: TASKFILE_IN */
TASKFILE_DPHASE_PIO_IN = 1, /* ide: TASKFILE_IN */
TASKFILE_DPHASE_PIO_OUT = 4, /* ide: TASKFILE_OUT */
};
struct reg_flags {
union {
unsigned lob_all : 8;
struct {
unsigned data : 1;
unsigned feat : 1;
unsigned lbal : 1;
unsigned nsect : 1;
unsigned lbam : 1;
unsigned lbah : 1;
unsigned dev : 1;
unsigned command : 1;
} lob;
};
union {
unsigned hob_all : 8;
struct {
unsigned data : 1;
unsigned feat : 1;
unsigned lbal : 1;
unsigned nsect : 1;
unsigned lbam : 1;
unsigned lbah : 1;
unsigned dev : 1;
unsigned command : 1;
} hob;
};
};
struct taskfile_regs {
__u8 data;
__u8 feat;
__u8 nsect;
__u8 lbal;
__u8 lbam;
__u8 lbah;
__u8 dev;
__u8 command;
};
struct hdio_taskfile {
struct taskfile_regs lob;
struct taskfile_regs hob;
struct reg_flags oflags;
struct reg_flags iflags;
int dphase;
int cmd_req; /* IDE command_type */
unsigned long obytes;
unsigned long ibytes;
__u16 data[0];
};
struct scsi_sg_io_hdr {
int interface_id;
int dxfer_direction;
unsigned char cmd_len;
unsigned char mx_sb_len;
unsigned short iovec_count;
unsigned int dxfer_len;
void * dxferp;
unsigned char * cmdp;
void * sbp;
unsigned int timeout;
unsigned int flags;
int pack_id;
void * usr_ptr;
unsigned char status;
unsigned char masked_status;
unsigned char msg_status;
unsigned char sb_len_wr;
unsigned short host_status;
unsigned short driver_status;
int resid;
unsigned int duration;
unsigned int info;
};
#ifndef SG_DXFER_NONE
#define SG_DXFER_NONE -1
#define SG_DXFER_TO_DEV -2
#define SG_DXFER_FROM_DEV -3
#define SG_DXFER_TO_FROM_DEV -4
#endif
#define SG_READ 0
#define SG_WRITE 1
#define SG_PIO 0
#define SG_DMA 1
#define SG_CHECK_CONDITION 0x02
#define SG_DRIVER_SENSE 0x08
#define SG_ATA_16 0x85
#define SG_ATA_16_LEN 16
#define SG_ATA_12 0xa1
#define SG_ATA_12_LEN 12
#define SG_ATA_LBA48 1
#define SG_ATA_PROTO_NON_DATA ( 3 << 1)
#define SG_ATA_PROTO_PIO_IN ( 4 << 1)
#define SG_ATA_PROTO_PIO_OUT ( 5 << 1)
#define SG_ATA_PROTO_DMA ( 6 << 1)
#define SG_ATA_PROTO_UDMA_IN (11 << 1) /* not yet supported in libata */
#define SG_ATA_PROTO_UDMA_OUT (12 << 1) /* not yet supported in libata */
void tf_init (struct ata_tf *tf, __u8 ata_op, __u64 lba, unsigned int nsect);
__u64 tf_to_lba (struct ata_tf *tf);
int sg16 (int fd, int rw, int dma, struct ata_tf *tf, void *data, unsigned int data_bytes, unsigned int timeout_secs);
int do_drive_cmd (int fd, unsigned char *args);
int do_taskfile_cmd (int fd, struct hdio_taskfile *r, unsigned int timeout_secs);
int dev_has_sgio (int fd);
void init_hdio_taskfile (struct hdio_taskfile *r, __u8 ata_op, int rw, int force_lba48,
__u64 lba, unsigned int nsect, int data_bytes);