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'.
7 * $Date: 2007-03-24 18:38:20 -0700 (Sat, 24 Mar 2007) $
11 /* What this does: Basically dumps out contents of:
12 * Mode Sense: Element Address Assignment Page (0x1d)
13 * 1Eh (Transport Geometry Parameters) has a bit which indicates is
14 * a robot is capable of rotating the media. It`s the
15 * `Rotate` bit, byte 2, bit 1.
16 * Device Capabilities page (0x1f)
17 * Inquiry -- prints full inquiry info.
22 * If there is a byte 55, we use the Exabyte extension to
23 * print out whether we have a bar code reader or not. This is
26 * Next, we request element status on the drives. We do not
27 * request volume tags though. If Exabyte
28 * extensions are supported, we report the following information for
32 * EXCEPT (with ASC and ASCQ), if there is a problem.
33 * SCSI address and LUN
34 * Tape drive Serial number
42 DEVICE_TYPE MediumChangerFD; /* historic purposes... */
46 /* A table for printing out the peripheral device type as ASCII. */
47 static char *PeripheralDeviceType[32] =
64 "Bridging Expander", /* 0x10 */
65 "Reserved", /* 0x11 */
66 "Reserved", /* 0x12 */
67 "Reserved", /* 0x13 */
68 "Reserved", /* 0x14 */
69 "Reserved", /* 0x15 */
70 "Reserved", /* 0x16 */
71 "Reserved", /* 0x17 */
72 "Reserved", /* 0x18 */
73 "Reserved", /* 0x19 */
74 "Reserved", /* 0x1a */
75 "Reserved", /* 0x1b */
76 "Reserved", /* 0x1c */
77 "Reserved", /* 0x1d */
78 "Reserved", /* 0x1e */
83 /* okay, now for the structure of an Element Address Assignment Page: */
87 unsigned char Page_Code;
88 unsigned char Parameter_Length;
89 unsigned char MediumTransportElementAddress[2];
90 unsigned char NumMediumTransportElements[2];
91 unsigned char FirstStorageElementAdddress[2];
92 unsigned char NumStorageElements[2];
93 unsigned char FirstImportExportElementAddress[2];
94 unsigned char NumImportExportElements[2];
95 unsigned char FirstDataTransferElementAddress[2];
96 unsigned char NumDataTransferElements[2];
97 unsigned char Reserved[2];
100 /* okay, now for the structure of a transport geometry
105 unsigned char Page_Code;
106 unsigned char ParameterLength;
107 unsigned char Rotate;
108 unsigned char ElementNumber; /* we don't care about this... */
112 /* Structure of the Device Capabilities Page: */
115 unsigned char Page_Code;
116 unsigned char ParameterLength;
117 unsigned char CanStore; /* bits about whether elements can store carts */
118 unsigned char SMC2_Caps;
119 unsigned char MT_Transfer; /* bits about whether mt->xx transfers work. */
120 unsigned char ST_Transfer; /* bits about whether st->xx transfers work. */
121 unsigned char IE_Transfer; /* bits about whether id->xx transfers work. */
122 unsigned char DT_Transfer; /* bits about whether DT->xx transfers work. */
123 unsigned char Reserved[4]; /* more reserved data */
124 unsigned char MT_Exchange; /* bits about whether mt->xx exchanges work. */
125 unsigned char ST_Exchange; /* bits about whether st->xx exchanges work. */
126 unsigned char IE_Exchange; /* bits about whether id->xx exchanges work. */
127 unsigned char DT_Exchange; /* bits about whether DT->xx exchanges work. */
128 unsigned char Reserved2[4]; /* more reserved data */
136 /* Okay, now for the inquiry information: */
138 static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
140 RequestSense_T RequestSense;
144 Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);
147 PrintRequestSense(&RequestSense);
148 FatalError("INQUIRY Command Failed\n");
151 printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
153 printf("Vendor ID: '");
154 for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
155 printf("%c", Inquiry->VendorIdentification[i]);
157 printf("'\nProduct ID: '");
158 for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
159 printf("%c", Inquiry->ProductIdentification[i]);
161 printf("'\nRevision: '");
162 for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
163 printf("%c", Inquiry->ProductRevisionLevel[i]);
169 /* check the attached-media-changer bit... */
170 printf("Attached Changer: Yes\n");
174 printf("Attached Changer: No\n");
177 /* Now see if we have a bar code flag: */
178 if (Inquiry->AdditionalLength > 50)
180 /* see if we have 56 bytes: */
181 if (Inquiry->VendorFlags & 1)
183 printf("Bar Code Reader: Yes\n");
187 printf("Bar Code Reader: No\n");
191 free(Inquiry); /* well, we're about to exit, but ... */
194 /*********** MODE SENSE *******************/
195 /* We need 3 different mode sense pages. This is a generic
196 * routine for obtaining mode sense pages.
200 *mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense)
203 unsigned char *input_buffer; /*the input buffer -- has junk prepended to
207 unsigned char *retval; /* the return value. */
212 FatalError("mode_sense(6) can only read up to 255 characters!\n");
215 input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */
217 /* clear the sense buffer: */
218 slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
220 /* returns an array of bytes in the page, or, if not possible, NULL. */
221 CDB[0] = 0x1a; /* Mode Sense(6) */
223 CDB[2] = pagenum; /* the page to read. */
225 CDB[4] = 255; /* allocation length. This does max of 256 bytes! */
228 if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,
229 input_buffer, 255, RequestSense) != 0)
231 #ifdef DEBUG_MODE_SENSE
232 fprintf(stderr,"Could not execute mode sense...\n");
235 return NULL; /* sorry, couldn't do it. */
238 /* First skip past any header.... */
239 tmp = input_buffer + 4 + input_buffer[3];
240 /* now find out real length of page... */
242 retval = xmalloc(pagelen);
243 /* and copy our data to the new page. */
244 for (i = 0; i < pagelen; i++)
248 /* okay, free our input buffer: */
253 /* Report the Element Address Assignment Page */
254 static void ReportEAAP(DEVICE_TYPE MediumChangerFD)
257 RequestSense_T RequestSense;
259 EAAP = (EAAP_Type *)mode_sense(MediumChangerFD, 0x1d, sizeof(EAAP_Type), &RequestSense);
263 PrintRequestSense(&RequestSense);
264 printf("EAAP: No\n");
268 /* we did get an EAAP, so do our thing: */
269 printf("EAAP: Yes\n");
270 printf("Number of Medium Transport Elements: %d\n", ( ((unsigned int)EAAP->NumMediumTransportElements[0]<<8) + (unsigned int)EAAP->NumMediumTransportElements[1]));
271 printf("Number of Storage Elements: %d\n", ( ((unsigned int)EAAP->NumStorageElements[0]<<8) + (unsigned int)EAAP->NumStorageElements[1]));
272 printf("Number of Import/Export Elements: %d\n", ( ((unsigned int)EAAP->NumImportExportElements[0]<<8) + (unsigned int)EAAP->NumImportExportElements[1]));
273 printf("Number of Data Transfer Elements: %d\n", ( ((unsigned int)EAAP->NumDataTransferElements[0]<<8) + (unsigned int)EAAP->NumDataTransferElements[1]));
278 /* See if we can get some invert information: */
280 static void Report_TGDP(DEVICE_TYPE MediumChangerFD)
284 RequestSense_T RequestSense;
286 result=(TGDP_Type *)mode_sense(MediumChangerFD,0x1e,255,&RequestSense);
290 printf("Transport Geometry Descriptor Page: No\n");
294 printf("Transport Geometry Descriptor Page: Yes\n");
296 /* Now print out the invert bit: */
297 if ( result->Rotate & 1 )
299 printf("Invertable: Yes\n");
303 printf("Invertable: No\n");
309 /* Okay, let's get the Device Capabilities Page. We don't care
310 * about much here, just whether 'mtx transfer' will work (i.e.,
314 void TransferExchangeTargets(unsigned char ucValue, char *szPrefix)
316 if (ucValue & DT_BIT)
318 printf("%sData Transfer", szPrefix);
321 if (ucValue & IE_BIT)
323 printf("%s%sImport/Export", ucValue > (IE_BIT | (IE_BIT - 1)) ? ", " : "", szPrefix);
326 if (ucValue & ST_BIT)
328 printf("%s%sStorage", ucValue > (ST_BIT | (ST_BIT - 1)) ? ", " : "", szPrefix);
331 if (ucValue & MT_BIT)
333 printf("%s%sMedium Transfer", ucValue > (MT_BIT | (MT_BIT - 1)) ? ", " : "", szPrefix);
337 static void Report_DCP(DEVICE_TYPE MediumChangerFD)
340 RequestSense_T RequestSense;
343 result=(DCP_Type *)mode_sense(MediumChangerFD,0x1f,sizeof(DCP_Type),&RequestSense);
346 printf("Device Configuration Page: No\n");
350 printf("Device Configuration Page: Yes\n");
354 if (result->CanStore & DT_BIT)
356 printf("Data Transfer");
359 if (result->CanStore & IE_BIT)
361 printf("%sImport/Export", result->CanStore > (IE_BIT | (IE_BIT - 1)) ? ", " : "");
364 if (result->CanStore & ST_BIT)
366 printf("%sStorage", result->CanStore > (ST_BIT | (ST_BIT - 1)) ? ", " : "");
369 if (result->CanStore & MT_BIT)
371 printf("%sMedium Transfer", result->CanStore > (MT_BIT | (MT_BIT - 1)) ? ", " : "");
376 printf("SCSI Media Changer (rev 2): ");
378 if (result->SMC2_Caps & 0x01)
382 printf("Volume Tag Reader Present: %s\n", result->SMC2_Caps & 0x02 ? "Yes" : "No");
383 printf("Auto-Clean Enabled: %s\n", result->SMC2_Caps & 0x04 ? "Yes" : "No");
390 printf("Transfer Medium Transport: ");
391 if ((result->MT_Transfer & 0x0F) != 0)
393 TransferExchangeTargets(result->MT_Transfer, "->");
400 printf("\nTransfer Storage: ");
401 if ((result->ST_Transfer & 0x0F) != 0)
403 TransferExchangeTargets(result->ST_Transfer, "->");
410 printf("\nTransfer Import/Export: ");
411 if ((result->IE_Transfer & 0x0F) != 0)
413 TransferExchangeTargets(result->IE_Transfer, "->");
420 printf("\nTransfer Data Transfer: ");
421 if ((result->DT_Transfer & 0x0F) != 0)
423 TransferExchangeTargets(result->DT_Transfer, "->");
430 printf("\nExchange Medium Transport: ");
431 if ((result->MT_Exchange & 0x0F) != 0)
433 TransferExchangeTargets(result->MT_Exchange, "<>");
440 printf("\nExchange Storage: ");
441 if ((result->ST_Exchange & 0x0F) != 0)
443 TransferExchangeTargets(result->ST_Exchange, "<>");
450 printf("\nExchange Import/Export: ");
451 if ((result->IE_Exchange & 0x0F) != 0)
453 TransferExchangeTargets(result->IE_Exchange, "<>");
460 printf("\nExchange Data Transfer: ");
461 if ((result->DT_Exchange & 0x0F) != 0)
463 TransferExchangeTargets(result->DT_Exchange, "<>");
477 FatalError("Usage: loaderinfo -f <generic-device>\n");
481 /* we only have one argument: "-f <device>". */
482 int main(int argc, char **argv)
490 fprintf(stderr,"argc=%d",argc);
494 if (strcmp(argv[1],"-f")!=0)
501 fd=SCSI_OpenDevice(filename);
503 /* Now to call the various routines: */