Skip to content

Instantly share code, notes, and snippets.

@sjorge
Last active January 12, 2018 22:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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 5, 2018

[root@carbon /opt/local/sbin]# smartctl -x /dev/rdsk/c0t5000CCA252CCB938d0 | grep APM
APM feature is:   Disabled
[root@carbon /opt/local/sbin]# hdsetparm c0t5000CCA252CCB938d0 APM 254
Setting APM to 254 for disk /dev/rdsk/c0t5000CCA252CCB938d0 ...
Success.
[root@carbon /opt/local/sbin]# smartctl -x /dev/rdsk/c0t5000CCA252CCB938d0 | grep APM
APM level is:     254 (maximum performance)

@mgerdts
Copy link

mgerdts commented Jan 5, 2018

Nice work for a C beginner. Some people start with helloworld.c. You... :)

Here are some comments that I would give to anyone else looking to integrate into illumos. I'm not sure if that is your intent or not. Aside from C style issues, most of the comments are related to string handling. This is particularly tricky in C.

  • Block comments start with /* on one line, end with */ on the last line, and have a * at column 2. All the *'s align.
  • Always indent with 8 character tabs. If you find your code is getting scrunched to the right half of 80 characters, that's a sign you probably should be splitting something out into a functions or you should be rethinking the algorithm.
  • Use /* */ rather than //. No, I don't have a good reason for this, just the way things are.
  • At line 42, there's no need to need check the length of argv[1]. The strlen() will read the first character, just as the comparison to '/' does later. Instead, just compare argv[1][0] to '/'.
  • Line 43 does not initialize disk_path[10]. If it happens to not be '\0', the strcat that follows will append at a different spot. That different spot may be outside of the allocated buffer. Use strcpy() instead - it will copy the 10 characters and terminate the string with '\0'.
  • Line 49 has a similar problem to 43. I have seen maybe one occurrence of strcpy(dst, src, strlen(src)) that wasn't a bug. In that case, dst was pre-initialized to contain all '\0' characters.
  • In a program like this, you aren't really worried about putting a KB or two on the stack. Rather than dynamically allocating memory, you could just declare disk_path[PATH_MAX].
  • Rather than the strcpy + strcat combination, I would typically use snprintf().
  • Line 64, split into two lines.

Here's a C style guide - there's probably a newer one somewhere. :) If you were to build this as part of an illumos build, the cstyle command run during the build would have complained about the style issues I mentioned and probably a few others.

https://www.cis.upenn.edu/~lee/06cse480/data/cstyle.ms.pdf

@sjorge
Copy link
Author

sjorge commented Jan 8, 2018

@mgerdts thanks for the feedback, I think I fixed most of the issues you brought up.
I'm not sure how to fix line 53 though?

Is there a way to run the cstyle command standalone?

@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