1 /* Copyright 2000 Enhanced Software Technologies Inc.
2 * Released under terms of the GNU General Public License as
3 * required by the license on 'mtxl.c'.
4 * $Date: 2007-03-24 18:14:01 -0700 (Sat, 24 Mar 2007) $
8 /*#define DEBUG_PARTITION */
11 /* What this does: This basically dumps out the contents of the following
14 * Inquiry -- prints full inquiry info. If it's not a tape drive, this is
21 * Log Sense: TapeAlert Page (if supported):
22 * TapeAlert:[message#]<Message> e.g. "TapeAlert:[22]Cleaning Cartridge Worn Out"
25 * Data Compression Page:
26 * DataCompEnabled:<yes|no>
27 * DataCompCapable:<yes|no>
28 * DataDeCompEnabled:<yes|no>
32 * Device Configuration Page:
34 * DevConfigComp:<#> -- the compression byte in device config page.
35 * EarlyWarningSize:<#> -- size of early warning buffer?
37 * Medium Partition Page:
41 * Partition[1]:<size>...
43 * Read Block Limits command:
44 * MinBlock:<#> -- Minimum block size.
45 * MaxBlock:<#> -- Maximum block size.
57 FatalError("Usage: tapeinfo -f <generic-device>\n");
60 /* A table for printing out the peripheral device type as ASCII. */
61 static char *PeripheralDeviceType[32] =
78 "Bridging Expander", /* 0x10 */
79 "Reserved", /* 0x11 */
80 "Reserved", /* 0x12 */
81 "Reserved", /* 0x13 */
82 "Reserved", /* 0x14 */
83 "Reserved", /* 0x15 */
84 "Reserved", /* 0x16 */
85 "Reserved", /* 0x17 */
86 "Reserved", /* 0x18 */
87 "Reserved", /* 0x19 */
88 "Reserved", /* 0x1a */
89 "Reserved", /* 0x1b */
90 "Reserved", /* 0x1c */
91 "Reserved", /* 0x1d */
92 "Reserved", /* 0x1e */
98 /* we call it MediumChangerFD for history reasons, sigh. */
100 /* now to print inquiry information: Copied from other one.... */
102 static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
104 RequestSense_T RequestSense;
108 Inquiry = RequestInquiry(MediumChangerFD, &RequestSense);
111 PrintRequestSense(&RequestSense);
112 FatalError("INQUIRY Command Failed\n");
115 printf("Product Type: %s\n", PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
117 printf("Vendor ID: '");
118 for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
119 printf("%c", Inquiry->VendorIdentification[i]);
121 printf("'\nProduct ID: '");
122 for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
123 printf("%c", Inquiry->ProductIdentification[i]);
125 printf("'\nRevision: '");
126 for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
127 printf("%c", Inquiry->ProductRevisionLevel[i]);
132 /* check the attached-media-changer bit... */
133 printf("Attached Changer API: Yes\n");
137 printf("Attached Changer API: No\n");
140 free(Inquiry); /* well, we're about to exit, but ... */
146 /* Okay, now for the Log Sense Tape Alert Page (if supported): */
147 #define TAPEALERT_SIZE 2048 /* max size of tapealert buffer. */
148 #define MAX_TAPE_ALERT 0x41
150 static char *tapealert_messages[] =
153 " Read: Having problems reading (slowing down)", /* 1 */
154 " Write: Having problems writing (losing capacity)", /* 2 */
155 " Hard Error: Uncorrectable read/write error", /* 3 */
156 " Media: Media Performance Degraded, Data Is At Risk", /* 4 */
157 " Read Failure: Tape faulty or tape drive broken", /* 5 */
158 "Write Failure: Tape faulty or tape drive broken", /* 6 */
159 " Media Life: The tape has reached the end of its useful life", /* 7 */
160 "Not Data Grade:Replace cartridge with one containing data grade tape",/*8*/
161 "Write Protect: Attempted to write to a write-protected cartridge",/*9 */
162 " No Removal: Cannot unload, initiator is preventing media removal", /*a*/
163 "Cleaning Media:Cannot back up or restore to a cleaning cartridge", /* b */
164 " Bad Format: The loaded tape contains data in an unsupported format", /*c */
165 " Snapped Tape: The data cartridge contains a broken tape", /* d */
168 "Undefined", /* 10 */
169 "Undefined", /* 11 */
170 "Undefined", /* 12 */
171 "Undefined", /* 13 */
172 " Clean Now: The tape drive neads cleaning NOW", /* 0x14 */
173 "Clean Periodic:The tape drive needs to be cleaned at next opportunity", /* 0x15 */
174 "Cleaning Media:Cannot clean because cleaning cartridge used up, insert new cleaning cartridge to clean the drive", /* 0x16 */
175 "Undefined", /* 0x17 */
176 "Undefined", /* 0x18 */
177 "Undefined", /* 0x19 */
178 "Undefined", /* 0x1a */
179 "Undefined", /* 0x1b */
180 "Undefined", /* 0x1c */
181 "Undefined", /* 0x1d */
182 " Hardware A: Tape drive has a problem not read/write related", /* 0x1e */
183 " Hardware B: Tape drive has a problem not read/write related", /* 0x1f */
184 " Interface: Problem with SCSI interface between tape drive and initiator", /* 0x20 */
185 " Eject Media: The current operation has failed. Eject and reload media", /* 0x21 */
186 "Download Fail: Attempt to download new firmware failed", /* 0x22 */
187 "Undefined", /* 0x23 */
188 "Undefined", /* 0x24 */
189 "Undefined", /* 0x25 */
190 "Undefined", /* 0x26 */
191 "Undefined", /* 0x27 */
192 "Loader Hardware A: Changer having problems communicating with tape drive", /* 0x28 40 */
193 "Loader Stray Tape: Stray tape left in drive from prior error", /* 0x29 41 */
194 "Loader Hardware B: Autoloader mechanism has a fault", /* 0x2a 42 */
195 " Loader Door: Loader door is open, please close it", /* 0x2b 43 */
196 "Undefined", /* 0x2c */
197 "Undefined", /* 0x2d */
198 "Undefined", /* 0x2e */
199 "Undefined", /* 0x2f */
200 "Undefined", /* 0x30 */
201 "Undefined", /* 0x31 */
202 "Undefined", /* 0x32 */
203 "Undefined", /* 0x33 */
204 "Undefined", /* 0x34 */
205 "Undefined", /* 0x35 */
206 "Undefined", /* 0x36 */
207 "Undefined", /* 0x37 */
208 "Undefined", /* 0x38 */
209 "Undefined", /* 0x39 */
210 "Undefined", /* 0x3a */
211 "Undefined", /* 0x3b */
212 "Undefined", /* 0x3c */
213 "Undefined", /* 0x3d */
214 "Undefined", /* 0x3e */
215 "Undefined", /* 0x3f */
216 "Undefined" /* 0x40 */
219 typedef struct TapeCapacityStruct
221 unsigned int partition0_remaining;
222 unsigned int partition1_remaining;
223 unsigned int partition0_size;
224 unsigned int partition1_size;
229 static void dump_data(unsigned char *data, int len)
233 fprintf(stderr,"DATA:");
234 PrintHex(1, data, len);
238 fprintf(stderr, "**NO DATA**\n");
244 /* Request the tape capacity page defined by some DAT autoloaders. */
246 static TapeCapacity *RequestTapeCapacity(DEVICE_TYPE fd, RequestSense_T *sense)
249 TapeCapacity *result;
252 unsigned char buffer[TAPEALERT_SIZE]; /* Overkill, but ... */
254 slow_bzero((char *)buffer,TAPEALERT_SIZE); /*zero it... */
256 /* now to create the CDB block: */
257 CDB[0] = 0x4d; /* Log Sense */
259 CDB[2] = 0x31; /* Tape Capacity Page. */
264 CDB[7] = TAPEALERT_SIZE >> 8 & 0xff; /* hi byte, allocation size */
265 CDB[8] = TAPEALERT_SIZE & 0xff; /* lo byte, allocation size */
266 CDB[9] = 0; /* reserved */
268 if (SCSI_ExecuteCommand(fd, Input, &CDB, 10, buffer, TAPEALERT_SIZE, sense) != 0)
270 /* fprintf(stderr,"RequestTapeCapacity: Command failed: Log Sense\n"); */
274 /* dump_data(buffer,64); */
276 /* okay, we have stuff in the result buffer: the first 4 bytes are a header:
277 * byte 0 should be 0x31, byte 1 == 0, bytes 2,3 tell how long the
280 if ((buffer[0]&0x3f) != 0x31)
282 /* fprintf(stderr,"RequestTapeCapacity: Invalid header for page (not 0x31).\n"); */
286 result_len = ((int)buffer[2] << 8) + buffer[3];
288 if (result_len != 32)
290 /* fprintf(stderr,"RequestTapeCapacity: Page was %d bytes long, not 32 bytes\n",result_len); */
291 return NULL; /* This Is Not The Page You're Looking For */
294 result = xmalloc(sizeof(TapeCapacity));
296 /* okay, now allocate data and move the buffer over there: */
298 /* 0 1 2 3 4 5 6 7 8 9
299 DATA: 31 00 00 20 00 01 4c 04 01 3a
300 10 11 12 13 14 15 16 17 18 19
301 DATA: 81 0c 00 02 4c 04 00 00 00 00
302 20 21 22 23 24 25 26 27 28 29
303 DATA: 00 03 4c 04 01 3f 4b 1f 00 04
305 DATA: 4c 04 00 00 00 00 00 00 00 00
306 DATA: 00 00 00 00 00 00 00 00 00 00
307 DATA: 00 00 00 00 00 00 00 00 00 00
311 result->partition0_remaining =
312 ((unsigned int)buffer[8] << 24) +
313 ((unsigned int)buffer[9] << 16) +
314 ((unsigned int)buffer[10] << 8) +
317 result->partition1_remaining =
318 ((unsigned int)buffer[16] << 24) +
319 ((unsigned int)buffer[17] << 16) +
320 ((unsigned int)buffer[18] << 8) +
323 result->partition0_size =
324 ((unsigned int)buffer[24] << 24) +
325 ((unsigned int)buffer[25] << 16) +
326 ((unsigned int)buffer[26] << 8) +
329 result->partition1_size =
330 ((unsigned int)buffer[32] << 24) +
331 ((unsigned int)buffer[33] << 16) +
332 ((unsigned int)buffer[34] << 8) +
340 struct tapealert_struct
346 static struct tapealert_struct *RequestTapeAlert(DEVICE_TYPE fd, RequestSense_T *sense)
350 struct tapealert_struct *result;
351 int i, tapealert_len, result_idx;
353 unsigned char buffer[TAPEALERT_SIZE];
354 unsigned char *walkptr;
356 slow_bzero((char *)buffer, TAPEALERT_SIZE); /*zero it... */
358 /* now to create the CDB block: */
359 CDB[0] = 0x4d; /* Log Sense */
361 CDB[2] = 0x2e; /* Tape Alert Page. */
366 CDB[7] = TAPEALERT_SIZE >> 8 & 0xff; /* hi byte, allocation size */
367 CDB[8] = TAPEALERT_SIZE & 0xff; /* lo byte, allocation size */
368 CDB[9] = 0; /* reserved */
370 if (SCSI_ExecuteCommand(fd,Input,&CDB,10,buffer,TAPEALERT_SIZE,sense)!=0)
375 result = xmalloc(sizeof(struct tapealert_struct));
377 /* okay, we have stuff in the result buffer: the first 4 bytes are a header:
378 * byte 0 should be 0x2e, byte 1 == 0, bytes 2,3 tell how long the
381 if ((buffer[0]&0x3f) != 0x2e)
388 tapealert_len = ((int)buffer[2] << 8) + buffer[3];
397 /* okay, now allocate data and move the buffer over there: */
398 result->length = MAX_TAPE_ALERT;
399 result->data = xzmalloc(MAX_TAPE_ALERT); /* alloc & zero. */
401 walkptr = &buffer[4];
404 while (i < tapealert_len)
406 result_idx=(((int)walkptr[0])<<8) + walkptr[1]; /* the parameter #. */
407 if (result_idx > 0 && result_idx < MAX_TAPE_ALERT)
411 result->data[result_idx] = 1;
415 result->data[result_idx] = 0;
418 fprintf(stderr,"Alert[0x%x]=%d\n",result_idx,result->data[result_idx]);
424 FatalError("Invalid tapealert page: %d\n",result_idx);
427 i = i + 4 + walkptr[3]; /* length byte! */
428 walkptr = walkptr + 4 + walkptr[3]; /* next! */
433 static void ReportTapeCapacity(DEVICE_TYPE fd)
435 /* we actually ignore a bad sense reading, like might happen if the
436 * tape drive does not support the tape capacity page.
439 RequestSense_T RequestSense;
441 TapeCapacity *result;
443 result=RequestTapeCapacity(fd,&RequestSense);
448 printf("Partition 0 Remaining Kbytes: %d\n", result->partition0_remaining);
449 printf("Partition 0 Size in Kbytes: %d\n", result->partition0_size);
451 if (result->partition1_size)
453 printf("Partition 1 Remaining Kbytes: %d\n", result->partition1_remaining);
454 printf("Partition 1 Size in Kbytes: %d\n", result->partition1_size);
462 static void ReportTapeAlert(DEVICE_TYPE fd)
464 /* we actually ignore a bad sense reading, like might happen if the
465 * tape drive does not support the tapealert page.
468 RequestSense_T RequestSense;
470 struct tapealert_struct *result;
473 result=RequestTapeAlert(fd,&RequestSense);
476 return; /* sorry. Don't print sense here. */
479 return; /* sorry, no alerts valid. */
481 for (i = 0; i < result->length; i++)
485 printf("TapeAlert[%d]: %s.\n", i, tapealert_messages[i]);
494 *mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense)
498 unsigned char *input_buffer;
500 unsigned char *retval;
505 FatalError("mode_sense(6) can only read up to 255 characters!\n");
508 input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */
510 /* clear the sense buffer: */
511 slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
513 /* returns an array of bytes in the page, or, if not possible, NULL. */
514 CDB[0] = 0x1a; /* Mode Sense(6) */
516 CDB[2] = pagenum; /* the page to read. */
518 CDB[4] = 255; /* allocation length. This does max of 256 bytes! */
521 if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, input_buffer, 255, RequestSense) != 0)
523 #ifdef DEBUG_MODE_SENSE
524 fprintf(stderr,"Could not execute mode sense...\n");
527 return NULL; /* sorry, couldn't do it. */
530 /* Oh hell, write protect is the only thing I have: always print
531 * it if our mode page was 0x0fh, before skipping past buffer:
532 * if the media is *NOT* write protected, just skip, sigh.
534 * Oh poops, the blocksize is reported in the block descriptor header
535 * < * too. Again, just print if our mode page was 0x0f...
541 if (input_buffer[2] & 0x80)
543 printf("WriteProtect: yes\n");
546 if (input_buffer[2] & 0x70)
548 printf("BufferedMode: yes\n");
551 if (input_buffer[1] )
553 printf("Medium Type: 0x%x\n", input_buffer[1]);
557 printf("Medium Type: Not Loaded\n");
560 printf("Density Code: 0x%x\n", input_buffer[4]);
561 /* Put out the block size: */
563 blocklen = ((int)input_buffer[9] << 16)+
564 ((int)input_buffer[10] << 8)+
567 printf("BlockSize: %d\n", blocklen);
570 /* First skip past any header.... */
571 tmp = input_buffer + 4 + input_buffer[3];
573 /* now find out real length of page... */
574 pagelen = tmp[1] + 2;
575 retval = xmalloc(pagelen);
577 /* and copy our data to the new page. */
578 for (i=0;i<pagelen;i++)
583 /* okay, free our input buffer: */
589 #define DCE_MASK 0x80
590 #define DCC_MASK 0x40
591 #define DDE_MASK 0x80
593 static void ReportCompressionPage(DEVICE_TYPE fd)
595 /* actually ignore a bad sense reading, like might happen if the tape
596 * drive does not support the mode sense compression page.
599 RequestSense_T RequestSense;
601 unsigned char *compression_page;
603 compression_page=mode_sense(fd,0x0f,16,&RequestSense);
605 if (!compression_page)
610 /* Okay, we now have the compression page. Now print stuff from it: */
611 printf("DataCompEnabled: %s\n", (compression_page[2] & DCE_MASK)? "yes" : "no");
612 printf("DataCompCapable: %s\n", (compression_page[2] & DCC_MASK)? "yes" : "no");
613 printf("DataDeCompEnabled: %s\n", (compression_page[3] & DDE_MASK)? "yes" : "no");
614 printf("CompType: 0x%x\n",
615 (compression_page[4] << 24) +
616 (compression_page[5] << 16) +
617 (compression_page[6] << 8) +
618 compression_page[7]);
620 printf("DeCompType: 0x%x\n",
621 (compression_page[8] << 24) +
622 (compression_page[9] << 16) +
623 (compression_page[10] << 8) +
624 compression_page[11]);
626 free(compression_page);
629 /* Now for the device configuration mode page: */
631 static void ReportConfigPage(DEVICE_TYPE fd)
633 RequestSense_T RequestSense;
634 unsigned char *config_page;
636 config_page = mode_sense(fd, 0x10, 16, &RequestSense);
640 /* Now to print the stuff: */
641 printf("ActivePartition: %d\n", config_page[3]);
643 /* The following does NOT work accurately on any tape drive I know of... */
644 /* printf("DevConfigComp: %s\n", config_page[14] ? "yes" : "no"); */
645 printf("EarlyWarningSize: %d\n",
646 (config_page[11] << 16) +
647 (config_page[12] << 8) +
651 /* ***************************************
652 * Medium Partition Page:
654 * The problem here, as we oh so graphically demonstrated during debugging
655 * of the Linux 'st' driver :-), is that there are actually *TWO* formats for
656 * the Medium Partition Page: There is the "long" format, where there is a
657 * partition size word for each partition on the page, and there is a "short"
658 * format, beloved of DAT drives, which only has a partition size word for
659 * partition #1 (and no partition size word for partition #0, and no
660 * provisions for any more partitions). So we must look at the size and
661 * # of partitions defined to know what to report as what.
663 ********************************************/
665 static void ReportPartitionPage(DEVICE_TYPE fd)
667 RequestSense_T RequestSense;
668 unsigned char *partition_page;
670 int num_parts,max_parts;
673 partition_page=mode_sense(fd,0x11,255,&RequestSense);
677 /* Okay, now we have either old format or new format: */
678 num_parts = partition_page[3];
679 max_parts = partition_page[2];
681 printf("NumPartitions: %d\n", num_parts);
682 printf("MaxPartitions: %d\n", max_parts);
686 /* if no additional partitions, then ... */
687 free(partition_page);
691 /* we know we have at least one partition if we got here. Check the
692 * page size field. If it is 8 or below, then we are the old format....
695 #ifdef DEBUG_PARTITION
696 fprintf(stderr,"partition_page[1]=%d\n",partition_page[1]);
699 if (partition_page[1]==8)
702 printf("Partition1: %d\n",(partition_page[8]<<8)+partition_page[9]);
707 for (i=0;i<=max_parts;i++)
709 #ifdef DEBUG_PARTITION
710 fprintf(stderr,"partition%d:[%d]%d [%d]%d\n", i, 8 + i * 2,
711 partition_page[8+i*2]<<8, 9+i*2,partition_page[9 + i * 2]);
714 printf("Partition%d: %d\n", i,
715 (partition_page[8 + i * 2] << 8) + partition_page[9 + i * 2]);
718 free(partition_page);
721 static void ReportSerialNumber(DEVICE_TYPE fd)
723 /* Actually ignore a bad sense reading, like might happen if the
724 tape drive does not support the inquiry page 0x80.
727 RequestSense_T sense;
730 #define WILD_SER_SIZE 30
731 unsigned char buffer[WILD_SER_SIZE]; /* just wildly overestimate serial# length! */
736 CDB[0] = 0x12; /* INQUIRY */
737 CDB[1] = 1; /* EVPD = 1 */
738 CDB[2] = 0x80; /* The serial # page, hopefully. */
739 CDB[3] = 0; /* reserved */
740 CDB[4] = WILD_SER_SIZE;
743 if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, &buffer, sizeof(buffer), &sense) != 0)
745 /* PrintRequestSense(&sense); */ /* zap debugging output :-) */
746 /* printf("No Serial Number: None\n"); */
750 /* okay, we have something in our buffer. Byte 3 should be the length of
751 the sernum field, and bytes 4 onward are the serial #. */
753 lim = (int)buffer[3];
754 bufptr = (char *)&(buffer[4]);
756 printf("SerialNumber: '");
764 /* Read Block Limits! */
766 void ReportBlockLimits(DEVICE_TYPE fd)
768 RequestSense_T sense;
770 unsigned char buffer[6];
772 CDB[0] = 0x05; /* READ_BLOCK_LIMITS */
775 CDB[3] = 0; /* 1-5 all unused. */
779 slow_bzero((char *)&sense,sizeof(RequestSense_T));
780 if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, buffer, 6, &sense) != 0)
785 /* okay, but if we did get a result, print it: */
786 printf("MinBlock: %d\n", (buffer[4] << 8) + buffer[5]);
787 printf("MaxBlock: %d\n", (buffer[1] << 16) + (buffer[2]<<8) + buffer[3]);
790 /* Do a READ_POSITION. This may not be always valid, but (shrug). */
791 void ReadPosition(DEVICE_TYPE fd)
793 RequestSense_T sense;
795 unsigned char buffer[20];
796 unsigned int position;
798 CDB[0] = 0x34; /* READ_POSITION */
801 CDB[3] = 0; /* 1-9 all unused. */
809 slow_bzero((char *)&sense, sizeof(RequestSense_T));
811 SCSI_Set_Timeout(2); /* set timeout to 2 seconds! */
813 /* if we don't get a result (e.g. we issue this to a disk drive), punt. */
814 if (SCSI_ExecuteCommand(fd, Input, &CDB, 10, buffer, 20, &sense) != 0)
819 SCSI_Default_Timeout(); /* reset it to 5 minutes, sigh! */
820 /* okay, but if we did get a result, print it: */
825 #define RBL_BYCU 0x10
828 #define RBL_PERR 0x02
830 /* If we have BOP, go ahead and print that. */
831 if (buffer[0]&RBL_BOP)
833 printf("BOP: yes\n");
836 /* if we have valid data, print it: */
837 if (buffer[0]&RBL_BPU)
839 printf("Block Position: -1");
843 position = (unsigned int)(((unsigned int)buffer[4] << 24) +
844 ((unsigned int)buffer[5] << 16) +
845 ((unsigned int)buffer[6] << 8) +
848 printf("Block Position: %d\n",position);
852 /* Test unit ready: This will tell us whether the tape drive
853 * is currently ready to read or write.
856 int TestUnitReady(DEVICE_TYPE fd)
858 RequestSense_T sense;
860 unsigned char buffer[6];
862 CDB[0] = 0x00; /* TEST_UNIT_READY */
865 CDB[3] = 0; /* 1-5 all unused. */
869 slow_bzero((char *)&sense,sizeof(RequestSense_T));
870 if (SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,0,&sense)!=0)
872 printf("Ready: no\n");
876 printf("Ready: yes\n");
880 /* We write a filemarks of 0 before going to grab position, in order
881 * to insure that data in the buffer is not a problem.
884 int WriteFileMarks(DEVICE_TYPE fd,int count)
886 RequestSense_T sense;
888 unsigned char buffer[6];
890 CDB[0] = 0x10; /* WRITE_FILE_MARKS */
892 CDB[2] = (unsigned char)(count >> 16);
893 CDB[3] = (unsigned char)(count >> 8);
894 CDB[4] = (unsigned char)count;
897 /* we really don't care if this command works or not, sigh. */
898 slow_bzero((char *)&sense, sizeof(RequestSense_T));
899 if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, buffer, 0, &sense) != 0)
908 /* This will get the SCSI ID and LUN of the target device, if such
909 * is available from the OS. Currently only Linux supports this,
910 * but other drivers could, if someone wants to write a
911 * SCSI_GetIDLun function for them.
913 #ifdef HAVE_GET_ID_LUN
915 static void ReportIDLun(DEVICE_TYPE fd)
919 scsi_id = SCSI_GetIDLun(fd);
920 printf("SCSI ID: %d\nSCSI LUN: %d\n", scsi_id->id, scsi_id->lun);
925 /* we only have one argument: "-f <device>". */
926 int main(int argc, char **argv)
935 fprintf(stderr,"argc=%d",argc);
939 if (strcmp(argv[1],"-f")!=0)
945 fd=SCSI_OpenDevice(filename);
947 /* Now to call the various routines: */
949 ReportSerialNumber(fd);
951 ReportBlockLimits(fd);
953 #ifdef HAVE_GET_ID_LUN
957 /* okay, we should only report position if the unit is ready :-(. */
958 if (TestUnitReady(fd))
960 ReportCompressionPage(fd);
962 ReportTapeCapacity(fd); /* only if we have it */
963 ReportConfigPage(fd); /* only valid if unit is ready. */
964 ReportPartitionPage(fd);