/* * Copyright (C) 2002 Emmanuel VARAGNAT * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // Include file generated by ./configure #ifdef HAVE_CONFIG_H #include #endif // Gettext includes #if ENABLE_NLS #include #define _(String) gettext (String) #else #define _(String) (String) #endif // Standard includes #include #include #include #include #include #include #include #include #include #include // Application specific includes #include "scsicmds.h" static void scsi_fixstring(unsigned char *s, int bytecount) { unsigned char *p; unsigned char *end; p = s; end = s + bytecount; /* strip leading blanks */ while (s != end && *s == ' ') ++s; /* compress internal blanks and strip trailing blanks */ while (s != end && *s) { if (*s++ != ' ' || (s != end && *s && *s != ' ')) *p++ = *(s-1); } /* wipe out trailing garbage */ while (p != end) *p++ = '\0'; } int scsi_SG_IO(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, unsigned char *sense, unsigned char sense_len, int dxfer_direction) { struct sg_io_hdr io_hdr; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmdp = cdb; io_hdr.cmd_len = cdb_len; io_hdr.dxfer_len = buffer_len; io_hdr.dxferp = buffer; io_hdr.mx_sb_len = sense_len; io_hdr.sbp = sense; io_hdr.dxfer_direction = dxfer_direction; io_hdr.timeout = 3000; /* 3 seconds should be ample */ return ioctl(device, SG_IO, &io_hdr); } int scsi_SEND_COMMAND(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, int dxfer_direction) { unsigned char buf[2048]; unsigned int inbufsize, outbufsize, ret; switch(dxfer_direction) { case SG_DXFER_FROM_DEV: inbufsize = 0; outbufsize = buffer_len; break; case SG_DXFER_TO_DEV: inbufsize = buffer_len; outbufsize = 0; break; default: inbufsize = 0; outbufsize = 0; break; } memcpy(buf, &inbufsize , sizeof(inbufsize)); memcpy(buf + sizeof(inbufsize), &outbufsize , sizeof(outbufsize)); memcpy(buf + sizeof(inbufsize) + sizeof(outbufsize), cdb, cdb_len); memcpy(buf + sizeof(inbufsize) + sizeof(outbufsize) + cdb_len, buffer, buffer_len); ret = ioctl(device, SCSI_IOCTL_SEND_COMMAND, buf); memcpy(buffer, buf + sizeof(inbufsize) + sizeof(outbufsize), buffer_len); return ret; } int scsi_command(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, int dxfer_direction) { static int SG_IO_supported = -1; int ret; if (SG_IO_supported == 1) return scsi_SG_IO(device, cdb, cdb_len, buffer, buffer_len, NULL, 0, dxfer_direction); else if (SG_IO_supported == 0) return scsi_SEND_COMMAND(device, cdb, cdb_len, buffer, buffer_len, dxfer_direction); else { ret = scsi_SG_IO(device, cdb, cdb_len, buffer, buffer_len, NULL, 0, dxfer_direction); if (ret == 0) { SG_IO_supported = 1; return ret; } else { SG_IO_supported = 0; return scsi_SEND_COMMAND(device, cdb, cdb_len, buffer, buffer_len, dxfer_direction); } } } int scsi_inquiry(int device, unsigned char *buffer) { unsigned char cdb[6]; memset(cdb, 0, sizeof(cdb)); cdb[0] = INQUIRY; cdb[4] = 36; /* should be 36 for unsafe devices (like USB mass storage stuff) * otherwise they can lock up! SPC sections 7.4 and 8.6 */ if (scsi_command(device, cdb, sizeof(cdb), buffer, cdb[4], SG_DXFER_FROM_DEV) != 0) return 1; else { scsi_fixstring(buffer + 8, 24); return 0; } } int scsi_modesense(int device, unsigned char pagenum, unsigned char *buffer, int buffer_len) { unsigned char cdb[6]; int ret; memset(cdb, 0, sizeof(cdb)); cdb[0] = MODE_SENSE; cdb[2] = pagenum; cdb[4] = 0xff; ret = scsi_command(device, cdb, sizeof(cdb), buffer, buffer_len, SG_DXFER_FROM_DEV); if (ret == 0) { if ((buffer[3] + 5) > buffer[0]) /* response length too short */ return -1; } return ret; } int scsi_modeselect(int device, char *buffer) { unsigned char cdb[6]; memset(cdb, 0, sizeof(cdb)); cdb[0] = MODE_SELECT; cdb[1] = 0x11; cdb[4] = buffer[0] + 1; memset(buffer, 0, 12); buffer[3] = 0x08; buffer[10] = 0x02; buffer[12] &= 0x3f; return scsi_command(device, cdb, sizeof(cdb), buffer, cdb[4], SG_DXFER_TO_DEV); } int scsi_logsense(int device, int pagenum, unsigned char *buffer, int buffer_len) { unsigned char cdb[10]; memset(cdb, 0, sizeof(cdb)); cdb[0] = LOG_SENSE; cdb[2] = 0x40 | pagenum; cdb[7] = 0x04; return scsi_command(device, cdb, sizeof(cdb), buffer, buffer_len, SG_DXFER_FROM_DEV); } int scsi_smartsupport(int device) { unsigned char buf[255]; if (scsi_modesense (device, EXCEPTIONS_CONTROL_PAGE, buf, sizeof(buf)) != 0) return 0; else return (buf[14] & 0x08) == 0; } int scsi_smartDEXCPTdisable(int device) { unsigned char buf[255]; if (scsi_modesense (device, EXCEPTIONS_CONTROL_PAGE, buf, sizeof(buf)) != 0) return 1; if (buf[14] & 0x08) { buf[14] &= 0xf7; buf[15] = 0x04; return scsi_modeselect (device, buf); } else return 0; }