/* * 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 #include #include #include #include #include #include #include #include #include #include /* #include */ /* 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] '\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; }