/* * This library implements a cleaner access system to the sg device * * $Id: scsi_tools.c,v 1.14 2001/02/16 14:52:52 root Exp $ * * Copyright (C) 2001 Kees Cook * cook@cpoint.net, http://outflux.net/ * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include #include #include #include #include #include #include #include #include "scsi_tools.h" #include "scsi_iface.h" #if 0 void printchars(u_char * str, int len) { int i; for (i=0;ifd, sizeof (cmdblk), 0, cmd, INQUIRY_REPLY_LEN, Inqbuffer)) { fprintf (stderr, "scsi_inquiry failed\n"); return NULL; } /* gather device characteristics */ if (ioctl(dev->fd, SG_GET_SCSI_ID, &dev->sginfo)<0) { perror("scsi_inquiry: SG_GET_SCSI_ID"); return NULL; } /* extract null-terminated text from inquery command */ strncpy(dev->vendor,Inqbuffer+SG_LEN+VENDOR_START,8); dev->vendor[8]='\0'; strncpy(dev->product,Inqbuffer+SG_LEN+VENDOR_START+8,16); dev->product[16]='\0'; strncpy(dev->version,Inqbuffer+SG_LEN+VENDOR_START+24,4); dev->version[4]='\0'; /* save the full inq buffer for vendor-specific stuff */ if (!(dev->fullinq=(char*)malloc(INQUIRY_REPLY_LEN+1))) { perror("scsi_inquiry: malloc"); return NULL; } memcpy(dev->fullinq,Inqbuffer+SG_LEN,INQUIRY_REPLY_LEN); dev->fullinq[INQUIRY_REPLY_LEN]='\0'; return dev; } int scsi_unitready (scsi_info * dev) { static u_char cmd[SG_LEN + 18]; /* SCSI command buffer */ /* request READY status */ static u_char cmdblk[TESTUNITREADY_CMDLEN] = { TESTUNITREADY_CMD, /* command */ 0, /* lun/reserved */ 0, /* reserved */ 0, /* reserved */ 0, /* reserved */ 0 }; /* reserved */ if (!dev) { fprintf(stderr,"scsi_unitready got NULL dev?!\n"); return 0; } memcpy (cmd + SG_LEN, cmdblk, sizeof (cmdblk)); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SG_LEN * +------------------+ */ if (waitfor_scsi_cmd (dev->fd, sizeof (cmdblk), 0, cmd, 0, NULL)) { fprintf (stderr, "scsi_testunitready failed\n"); return 0; /* not ready */ } return *(((struct sg_header *) cmd)->sense_buffer + ADD_SENSECODE) != NO_MEDIA_SC || *(((struct sg_header *) cmd)->sense_buffer + ADD_SC_QUALIFIER) != NO_MEDIA_SCQ; } scsi_info * scsi_open_name(char * filename) { scsi_info * dev; int flags; if (!(dev=(scsi_info*)calloc(1,sizeof(scsi_info)))) { perror("scsi_open malloc"); return NULL; } if (!filename) { fprintf(stderr,"scsi_open got NULL filename?!\n"); return NULL; } if ((dev->fd = open (filename, O_RDWR | O_EXCL | O_NONBLOCK))<0) { if (errno != ENOENT && errno != ENXIO) { fprintf(stderr,"scsi_open('%s'): %s\n",filename, strerror(errno)); } free(dev); return NULL; } if ((flags = fcntl(dev->fd, F_GETFL))<0) { perror("scsi_open: fcntl(F_GETFL)"); goto failed; } if (fcntl(dev->fd, F_SETFL, flags & (~ O_NONBLOCK))<0) { perror("scsi_open: fcntl(F_SETFL)"); goto failed; } /* perform inquiry */ if (!scsi_inquiry(dev)) { fprintf(stderr,"scsi_open: failed inquiry\n"); goto failed; } dev->filename=strdup(filename); return dev; failed: scsi_close(dev); return NULL; } scsi_info * scsi_open_id(int host, int chan, int id, int lun) { scsi_info * dev; char sgfile[24]; int i; for (i=0;i<128;i++) { sprintf(sgfile,"/dev/sg%d",i); if ((dev = scsi_open_name(sgfile))!=NULL) { if ( dev->sginfo.host_no==host && dev->sginfo.channel==chan && dev->sginfo.scsi_id==id && dev->sginfo.lun==lun) return dev; scsi_close(dev); } } return NULL; } void scsi_close(scsi_info * dev) { if (!dev) { fprintf(stderr,"scsi_close got NULL dev?!\n"); return; } close(dev->fd); if (dev->filename) free(dev->filename); if (dev->fullinq) free(dev->fullinq); free(dev); } /* max str length is 13 */ char * scsi_type(int type) { switch (type) { case TYPE_DISK: return "Disk"; case TYPE_TAPE: return "Tape"; case TYPE_PROCESSOR: return "Processor"; case TYPE_WORM: return "Worm"; case TYPE_ROM: return "CD-Rom"; case TYPE_SCANNER: return "Scanner"; case TYPE_MOD: return "Mag-optical"; case TYPE_MEDIUM_CHANGER: return "Changer"; case TYPE_COMM: return "Communication"; case TYPE_ENCLOSURE: return "Enclosure"; case TYPE_NO_LUN: return "No Lun"; default: return "Unknown"; } }