/* * This library works on the Linux sg device driver * * $Id: scsi_iface.c,v 1.4 2001/02/16 00:29:33 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 /* ioctl */ #define __USE_XOPEN #define __USE_GNU #include #include "scsi_iface.h" /* start our scsi command (need to know output size) */ int start_scsi_cmd ( int fd, /* sg fd */ unsigned cmd_len, /* command length */ unsigned in_size, /* input data size */ unsigned char *i_buff, /* input buffer */ unsigned out_size /* output data size */ ) { int status = 0; struct sg_header *sg_hd; /* safety checks */ if (!cmd_len) { fprintf(stderr,"start_scsi_cmd: cmd_len == 0\n"); return -1; /* need a cmd_len != 0 */ } if (!i_buff) { fprintf(stderr,"start_scsi_cmd: i_buff == NULL\n"); return -1; /* need an input buffer != NULL */ } /* keep the packet size under 4k */ if (SG_LEN + cmd_len + in_size > MAX_PACKET) { fprintf(stderr,"packet too large\n"); return -1; } /* generic scsi device header construction */ sg_hd = (struct sg_header *) i_buff; /* useful stuff */ sg_hd->reply_len = SG_LEN + out_size; sg_hd->twelve_byte = (cmd_len == 12); /* should be set */ /* not really used stuff */ sg_hd->other_flags = 0; /* not used */ sg_hd->result = 0; sg_hd->pack_id = 0; /* ignored stuff */ #if 0 sg_hd->pack_len = SG_LEN + cmd_len + in_size; /* not necessary */ #endif /* send command */ /* FIXME: handle EAGAIN errno */ status = write (fd, i_buff, SG_LEN + cmd_len + in_size); if (status < 0 || status != SG_LEN + cmd_len + in_size) { /* some error happened */ fprintf (stderr, "write(sg fd %d) result = 0x%x cmd = 0x%x: ", fd, sg_hd->result, i_buff[SG_LEN]); perror (""); return status; } return 0; } /* get results from last scsi cmd (need output buffer and size) */ int finish_scsi_cmd ( int fd, /* sg fd */ unsigned out_size, /* output data size */ unsigned char *o_buff /* output buffer */ ) { int status = 0; struct sg_header *sg_hd; /* safety checks */ if (SG_LEN + out_size > MAX_PACKET) { fprintf(stderr,"finish_scsi_cmd: packet too large\n"); return -1; } if (!o_buff) { fprintf(stderr,"finish_scsi_cmd: o_buff == NULL\n"); return -1; } /* retrieve result */ /* FIXME: handle EINTR errno */ status = read (fd, o_buff, SG_LEN + out_size); if (status < 0 || status != SG_LEN + out_size) { /* some error happened */ fprintf (stderr, "read(sg fd %d) result = 0x%x cmd = 0x%x\n", fd, sg_hd->result, o_buff[SG_LEN]); fprintf (stderr, "read(sg fd %d) sense " "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", fd, sg_hd->sense_buffer[0], sg_hd->sense_buffer[1], sg_hd->sense_buffer[2], sg_hd->sense_buffer[3], sg_hd->sense_buffer[4], sg_hd->sense_buffer[5], sg_hd->sense_buffer[6], sg_hd->sense_buffer[7], sg_hd->sense_buffer[8], sg_hd->sense_buffer[9], sg_hd->sense_buffer[10], sg_hd->sense_buffer[11], sg_hd->sense_buffer[12], sg_hd->sense_buffer[13], sg_hd->sense_buffer[14], sg_hd->sense_buffer[15]); if (status < 0) perror (""); } /* Look if we got what we expected to get */ if (status == SG_LEN + out_size) status = 0; /* got them all */ return status; /* 0 means no error */ } /* process a complete scsi cmd. Use the generic scsi interface. */ int waitfor_scsi_cmd ( int fd, /* sg fd */ unsigned cmd_len, /* command length */ unsigned in_size, /* input data size */ unsigned char *i_buff, /* input buffer */ unsigned out_size, /* output data size */ unsigned char *o_buff /* output buffer */ ) { int result; static char buf[MAX_PACKET+SG_LEN]; if ((result=start_scsi_cmd(fd, cmd_len, in_size, i_buff, out_size))!=0) { fprintf(stderr,"start_scsi_cmd failed\n"); return result; } if (!o_buff) { memset(buf,0,sizeof(buf)); o_buff=buf; } if ((result=finish_scsi_cmd(fd, out_size, o_buff))!=0) { fprintf(stderr,"finish_scsi_cmd failed\n"); return result; } return 0; }