diff options
Diffstat (limited to 'examples/scsi_inquiry.c')
-rw-r--r-- | examples/scsi_inquiry.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/examples/scsi_inquiry.c b/examples/scsi_inquiry.c new file mode 100644 index 00000000..99497490 --- /dev/null +++ b/examples/scsi_inquiry.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 1999-2018 D. Gilbert + * 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, or (at your option) + * any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") + * device driver. + * This program does a SCSI inquiry command on the given device and + * outputs some of the result. This program highlights the use of the + * SCSI_IOCTL_SEND_COMMAND ioctl. This should be able to be applied to + * any SCSI device file descriptor (not just one related to sg). [Whether + * this is a good idea on a disk while it is mounted is debatable. + * No detrimental effects when this was tested ...] + * + * Version 0.16 20181207 + */ + +#include <unistd.h> +#include <signal.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <scsi/scsi.h> +/* #include <scsi/scsi_ioctl.h> */ /* glibc hides this file sometimes */ + +typedef struct my_scsi_ioctl_command { + unsigned int inlen; /* _excluding_ scsi command length */ + unsigned int outlen; + unsigned char data[1]; /* was 0 but that's not ISO C!! */ + /* on input, scsi command starts here then opt. data */ +} My_Scsi_Ioctl_Command; + +#define OFF (2 * sizeof(unsigned int)) + +#ifndef SCSI_IOCTL_SEND_COMMAND +#define SCSI_IOCTL_SEND_COMMAND 1 +#endif + +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6 +#define INQUIRY_REPLY_LEN 96 + + +int main(int argc, char * argv[]) +{ + int s_fd, res, k, to; + unsigned char inq_cdb [INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, + INQUIRY_REPLY_LEN, 0}; + unsigned char * inqBuff = (unsigned char *) + malloc(OFF + sizeof(inq_cdb) + 512); + unsigned char * buffp = inqBuff + OFF; + My_Scsi_Ioctl_Command * ishp = (My_Scsi_Ioctl_Command *)inqBuff; + char * file_name = 0; + int do_nonblock = 0; + int oflags = 0; + + for (k = 1; k < argc; ++k) { + if (0 == strcmp(argv[k], "-n")) + do_nonblock = 1; + else if (*argv[k] != '-') + file_name = argv[k]; + else { + printf("Unrecognized argument '%s'\n", argv[k]); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'scsi_inquiry [-n] <scsi_device>'\n"); + printf(" where: -n open device in non-blocking mode\n"); + printf(" Examples: scsi_inquiry /dev/sda\n"); + printf(" scsi_inquiry /dev/sg0\n"); + printf(" scsi_inquiry -n /dev/scd0\n"); + return 1; + } + + if (do_nonblock) + oflags = O_NONBLOCK; + s_fd = open(file_name, oflags | O_RDWR); + if (s_fd < 0) { + if ((EROFS == errno) || (EACCES == errno)) { + s_fd = open(file_name, oflags | O_RDONLY); + if (s_fd < 0) { + perror("scsi_inquiry: open error"); + return 1; + } + } + else { + perror("scsi_inquiry: open error"); + return 1; + } + } + /* Don't worry, being very careful not to write to a none-scsi file ... */ + res = ioctl(s_fd, SCSI_IOCTL_GET_BUS_NUMBER, &to); + if (res < 0) { + /* perror("ioctl on scsi device, error"); */ + printf("scsi_inquiry: not a scsi device\n"); + return 1; + } + + ishp->inlen = 0; + ishp->outlen = INQUIRY_REPLY_LEN; + memcpy(buffp, inq_cdb, INQUIRY_CMDLEN); + res = ioctl(s_fd, SCSI_IOCTL_SEND_COMMAND, inqBuff); + if (0 == res) { + to = (int)*(buffp + 7); + printf(" %.8s %.16s %.4s, byte_7=0x%x\n", buffp + 8, + buffp + 16, buffp + 32, to); + } + else if (res < 0) + perror("scsi_inquiry: SCSI_IOCTL_SEND_COMMAND err"); + else + printf("scsi_inquiry: SCSI_IOCTL_SEND_COMMAND status=0x%x\n", res); + + res = close(s_fd); + if (res < 0) { + perror("scsi_inquiry: close error"); + return 1; + } + return 0; +} |