Skip to content

Instantly share code, notes, and snippets.

@sjorge
Last active January 12, 2018 22:01
Show Gist options
  • Save sjorge/c3e438b00cc73543e25aa049423cbfe8 to your computer and use it in GitHub Desktop.
Save sjorge/c3e438b00cc73543e25aa049423cbfe8 to your computer and use it in GitHub Desktop.
/*
* HD Set Parm
* ----------------------------
* Based on setapm and setaam from:
* http://solaris.kuehnke.de/archives/23-Set-APM-and-AAM-feature-configuration \
* -attributes-for-disks-on-Solaris.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <sys/scsi/impl/uscsi.h>
uchar_t sf_enable_apm_cdb[12] = { 0xa1, 0x06, 0x0c, 0x05, 0x24, 0x00,
0x00, 0x00, 0x00, 0xef, 0x00, 0x00 };
uchar_t sf_enable_aam_cdb[12] = { 0xa1, 0x06, 0x0c, 0x42, 0xd0, 0x00,
0x00, 0x00, 0x00, 0xef, 0x00, 0x00 };
static void
usage(int argc, char *argv[])
{
fprintf(stderr, "Usage: %s <device> <APM|AAM> <Level>\n", argv[0]);
fprintf(stderr, " where Level = [0..254] (0=Disable APM/AAM)\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int i;
int disk_fd;
int plevel;
char pname[4];
char disk_path[PATH_MAX];
uchar_t sf_enable_axm_cdb[12];
struct uscsi_cmd scsi_cmd;
/*
* validate input
*/
if (argc != 4) {
/* incorrect argument count */
usage(argc, argv);
}
if (argv[1][0] != '/') {
/* we have a bare disk name */
snprintf(disk_path, sizeof (disk_path),
"/dev/rdsk/%s", argv[1]);
} else {
/* we have an absolute disk name */
if (strlcpy(disk_path, argv[1], sizeof (disk_path)) >=
sizeof (disk_path)) {
perror("device path is to long!");
exit(EXIT_FAILURE);
}
}
if ((disk_fd = open(disk_path, O_RDWR | O_NDELAY)) < 0) {
/* unable to open device, does it exists? */
perror("Failed to open device");
exit(EXIT_FAILURE);
}
if (strlen(argv[2]) != 3) {
/* pname is not 3 long */
usage(argc, argv);
}
strlcpy(pname, argv[2], sizeof (pname));
if ((strncasecmp(pname, "APM", 3) != 0) &&
(strncasecmp(pname, "AAM", 3) != 0)) {
usage(argc, argv);
}
for (i = 0; i < strlen(pname); i++) {
/* make the str pname to be upper case */
/* FIXME: can this be cleaned up ? */
pname[i] = toupper(pname[i]);
}
if (sscanf(argv[3], "%d", &plevel) != 1) { /* failed to read plevel */
usage(argc, argv);
}
if (plevel < 0 || plevel > 254) {
/* plevel not in acceptable range */
usage(argc, argv);
}
/* print notice */
fprintf(stdout, "Setting %s to %d for disk %s ...\n",
pname, plevel, disk_path);
/* copy correct template */
if (strncasecmp(pname, "APM", 3) == 0) {
memcpy(sf_enable_axm_cdb, sf_enable_apm_cdb, \
sizeof (sf_enable_axm_cdb));
} else {
memcpy(sf_enable_axm_cdb, sf_enable_aam_cdb, \
sizeof (sf_enable_axm_cdb));
}
/* insert plevel */
sf_enable_axm_cdb[4] = (unsigned char)plevel;
if (plevel == 0) {
sf_enable_axm_cdb[3] = 0x85;
}
/* prepare scsi command */
memset(&scsi_cmd, 0, sizeof (scsi_cmd));
scsi_cmd.uscsi_cdblen = 12;
scsi_cmd.uscsi_timeout = 30;
scsi_cmd.uscsi_flags = USCSI_READ | USCSI_SILENT | USCSI_ISOLATE;
scsi_cmd.uscsi_cdb = (caddr_t)sf_enable_axm_cdb;
scsi_cmd.uscsi_rqbuf = NULL;
scsi_cmd.uscsi_rqlen = 0;
/* send scsi command */
if (ioctl(disk_fd, USCSICMD, &scsi_cmd) < 0) {
close(disk_fd);
perror("USCSICMD ioctl failed");
exit(EXIT_FAILURE);
}
/* cleanup */
close(disk_fd);
fprintf(stdout, "Success.\n");
return (EXIT_SUCCESS);
}
/* vim: set tabstop=8 noexpandtab shiftwidth=8 softtabstop=8 : */
@sjorge
Copy link
Author

sjorge commented Jan 8, 2018

random notes: strxxx vs strnxxx, the n will usually operate to the '\n' termination
e.g. strlen("abc") will be 3, strnlen("abc") will be 4... because "abc" is actually char ['a', 'b', 'c', '\n']

@sjorge
Copy link
Author

sjorge commented Jan 12, 2018

@mgerdts is sys/ioctl.h and unistd.h needed? Compiles and seems to run fine without those, but IIRC close () is provided by unistd.h? And I thought the ioctl command came from ioctl.h?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment