/* Example program to demonstrate the generic SCSI interface */ #include #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define SCSI_OFF sizeof(struct sg_header) #define RAID_SENSE 0xda #define MODE_SENSE_10 0x5a #define INQUIRY_REPLY_LEN 32 char DEVICE[20]="/dev/sga"; char *DeviceTable[7] ={"/dev/sga", "/dev/sgb", "/dev/sgc", "/dev/sgd", "/dev/sge", "/dev/sgf", "/dev/sgg"}; static unsigned char cmd[SCSI_OFF + 18]; /* SCSI command buffer */ int fd; /* SCSI device/file descriptor */ unsigned char SCSIBuffer[ SCSI_OFF + 0x8000 ]; /* process a complete SCSI cmd. Use the generic SCSI interface. */ static int handle_SCSI_cmd(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 status = 0; struct sg_header *sg_hd; /* safety checks */ if (!cmd_len) return -1; /* need a cmd_len != 0 */ if (!i_buff) return -1; /* need an input buffer != NULL */ #ifdef SG_BIG_BUFF if (SCSI_OFF + cmd_len + in_size > SG_BIG_BUFF) return -1; if (SCSI_OFF + out_size > SG_BIG_BUFF) return -1; #else if (SCSI_OFF + cmd_len + in_size > 4096) return -1; if (SCSI_OFF + out_size > 4096) return -1; #endif if (!o_buff) out_size = 0; /* no output buffer, no output size */ /* generic SCSI device header construction */ sg_hd = (struct sg_header *) i_buff; sg_hd->reply_len = SCSI_OFF + out_size; sg_hd->twelve_byte = cmd_len == 12; sg_hd->result = 0; #if 0 sg_hd->pack_len = SCSI_OFF + cmd_len + in_size; /* not necessary */ sg_hd->pack_id; /* not used */ sg_hd->other_flags; /* not used */ #endif /* send command */ status = write( fd, i_buff, SCSI_OFF + cmd_len + in_size ); if ( status < 0 || status != SCSI_OFF + cmd_len + in_size || sg_hd->result ) { /* some error happened */ fprintf( stdout, "write(generic) result = 0x%x cmd = 0x%x\n", sg_hd->result, i_buff[SCSI_OFF] ); perror(""); return status; } if (!o_buff) o_buff = i_buff; /* buffer pointer check */ /* retrieve result */ status = read( fd, o_buff, SCSI_OFF + out_size); if ( status < 0 || status != SCSI_OFF + out_size || sg_hd->result ) { /* some error happened */ fprintf( stdout, "read(generic) status = 0x%x, result = 0x%x, " "cmd = 0x%x\n", status, sg_hd->result, o_buff[SCSI_OFF] ); fprintf( stdout, "read(generic) sense " "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", 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 == SCSI_OFF + out_size) status = 0; /* got them all */ return status; /* 0 means no error */ } static unsigned char *Inquiry ( void ) { unsigned char cmdblk [ 6 ] = { INQUIRY, /* command */ 0, /* lun/reserved */ 0, /* page code */ 0, /* reserved */ INQUIRY_REPLY_LEN, /* allocation length */ 0 }; /* reserved/flag/link */ memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) ); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SCSI_OFF * +------------------+ */ if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd, INQUIRY_REPLY_LEN , SCSIBuffer )) { fprintf( stdout, "Inquiry failed\n" ); return NULL; } return (SCSIBuffer + SCSI_OFF); } static unsigned char *ModeSense ( void ) { unsigned char TransferLength=1; unsigned char cmdblk [ 6 ] = { MODE_SENSE, /* command */ 0, /* lun/reserved */ 0x3e, /* page code */ 0, /* reserved */ TransferLength, /* allocation length */ 0 }; /* reserved/flag/link */ memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) ); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SCSI_OFF * +------------------+ */ if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd, TransferLength, SCSIBuffer )) { fprintf( stdout, "Mode sense failed\n" ); exit(2); } TransferLength=SCSIBuffer[SCSI_OFF]; cmdblk[4]=TransferLength+1; memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) ); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SCSI_OFF * +------------------+ */ if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd, TransferLength, SCSIBuffer )) { fprintf( stdout, "Mode sense failed\n" ); return NULL; } return (SCSIBuffer + SCSI_OFF); } static unsigned char *ModeSense3d ( void ) { unsigned TransferLength=2; unsigned char cmdblk [ 10 ] = { MODE_SENSE_10, /* command */ 0, /* lun/reserved */ 0x3d, /* page code */ 0, /* reserved */ 0, 0, 0, 0, TransferLength, /* allocation length */ 0 }; /* reserved/flag/link */ memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) ); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SCSI_OFF * +------------------+ */ if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd, TransferLength, SCSIBuffer )) { fprintf( stdout, "Mode sense failed\n" ); exit(2); } TransferLength=SCSIBuffer[SCSI_OFF]*0x100+SCSIBuffer[SCSI_OFF+1]; cmdblk[7]=SCSIBuffer[SCSI_OFF]; cmdblk[8]=SCSIBuffer[SCSI_OFF+1]; memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) ); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SCSI_OFF * +------------------+ */ if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd, TransferLength, SCSIBuffer )) { fprintf( stdout, "Mode sense failed\n" ); return NULL; } return (SCSIBuffer + SCSI_OFF); } static unsigned char *RaidSense ( unsigned char PageNumber ) { unsigned char TransferLength=0xff; unsigned char cmdblk [ 12 ] = { RAID_SENSE, /* command */ 0, /* lun/reserved */ PageNumber, /* page code */ 0, /* reserved */ 0, /* reserved */ 0, /* reserved */ 0, /* reserved */ 0, /* allocation length */ 0, /* allocation length */ TransferLength, /* allocation length */ 0, 0 }; memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) ); /* * +------------------+ * | struct sg_header | <- cmd * +------------------+ * | copy of cmdblk | <- cmd + SCSI_OFF * +------------------+ */ if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd, TransferLength, SCSIBuffer )) { fprintf( stdout, "RAID sense failed\n" ); return NULL; } return (SCSIBuffer + SCSI_OFF); } unsigned char isSCSIdevice(char *DeviceName) { if(strncmp(DeviceName,"/dev/sg",7)) return FALSE; else return TRUE; } /*----------------------------main routine----------------------------*/ void main( int argc , char **argv ) { unsigned char *pDataBuffer; long Loop; unsigned char DeviceNumber; unsigned char Func; unsigned char i=0; if(argc < 3) { printf("usage: %s Device Function\n",argv[0]); return; } if (isdigit(argv[1][0])) { DeviceNumber = (unsigned char)atoi(argv[1]); if(DeviceNumber>6) { printf("Invalid Device Number!\n"); return; } strcpy(DEVICE,DeviceTable[DeviceNumber]); } else { strcpy(DEVICE,argv[1]); for(Loop=0;Loop