1 /* Copyright 2000 Enhanced Software Technologies Inc.
2 * Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
3 * Released under terms of the GNU General Public License as
4 * required by the license on 'mtxl.c'.
8 * $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
12 /* What this does: Basically dumps out contents of:
13 * Mode Sense: Element Address Assignment Page (0x1d)
14 * 1Eh (Transport Geometry Parameters) has a bit which indicates is
15 * a robot is capable of rotating the media. It`s the
16 * `Rotate` bit, byte 2, bit 1.
17 * Device Capabilities page (0x1f)
18 * Inquiry -- prints full inquiry info.
23 * If there is a byte 55, we use the Exabyte extension to
24 * print out whether we have a bar code reader or not. This is
27 * Next, we request element status on the drives. We do not
28 * request volume tags though. If Exabyte
29 * extensions are supported, we report the following information for
33 * EXCEPT (with ASC and ASCQ), if there is a problem.
34 * SCSI address and LUN
35 * Tape drive Serial number
43 DEVICE_TYPE MediumChangerFD; /* historic purposes... */
47 /* A table for printing out the peripheral device type as ASCII. */
48 static char *PeripheralDeviceType[32] =
65 "Bridging Expander", /* 0x10 */
66 "Reserved", /* 0x11 */
67 "Reserved", /* 0x12 */
68 "Reserved", /* 0x13 */
69 "Reserved", /* 0x14 */
70 "Reserved", /* 0x15 */
71 "Reserved", /* 0x16 */
72 "Reserved", /* 0x17 */
73 "Reserved", /* 0x18 */
74 "Reserved", /* 0x19 */
75 "Reserved", /* 0x1a */
76 "Reserved", /* 0x1b */
77 "Reserved", /* 0x1c */
78 "Reserved", /* 0x1d */
79 "Reserved", /* 0x1e */
84 /* okay, now for the structure of an Element Address Assignment Page: */
88 unsigned char Page_Code;
89 unsigned char Parameter_Length;
90 unsigned char MediumTransportElementAddress[2];
91 unsigned char NumMediumTransportElements[2];
92 unsigned char FirstStorageElementAdddress[2];
93 unsigned char NumStorageElements[2];
94 unsigned char FirstImportExportElementAddress[2];
95 unsigned char NumImportExportElements[2];
96 unsigned char FirstDataTransferElementAddress[2];
97 unsigned char NumDataTransferElements[2];
98 unsigned char Reserved[2];
101 /* okay, now for the structure of a transport geometry
106 unsigned char Page_Code;
107 unsigned char ParameterLength;
108 unsigned char Rotate;
109 unsigned char ElementNumber; /* we don't care about this... */
113 /* Structure of the Device Capabilities Page: */
116 unsigned char Page_Code;
117 unsigned char ParameterLength;
118 unsigned char CanStore; /* bits about whether elements can store carts */
119 unsigned char SMC2_Caps;
120 unsigned char MT_Transfer; /* bits about whether mt->xx transfers work. */
121 unsigned char ST_Transfer; /* bits about whether st->xx transfers work. */
122 unsigned char IE_Transfer; /* bits about whether id->xx transfers work. */
123 unsigned char DT_Transfer; /* bits about whether DT->xx transfers work. */
124 unsigned char Reserved[4]; /* more reserved data */
125 unsigned char MT_Exchange; /* bits about whether mt->xx exchanges work. */
126 unsigned char ST_Exchange; /* bits about whether st->xx exchanges work. */
127 unsigned char IE_Exchange; /* bits about whether id->xx exchanges work. */
128 unsigned char DT_Exchange; /* bits about whether DT->xx exchanges work. */
129 unsigned char Reserved2[4]; /* more reserved data */
137 /* Okay, now for the inquiry information: */
139 static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
141 RequestSense_T RequestSense;
145 Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);
148 PrintRequestSense(&RequestSense);
149 FatalError("INQUIRY Command Failed\n");
152 printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
154 printf("Vendor ID: '");
155 for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
156 printf("%c", Inquiry->VendorIdentification[i]);
158 printf("'\nProduct ID: '");
159 for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
160 printf("%c", Inquiry->ProductIdentification[i]);
162 printf("'\nRevision: '");
163 for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
164 printf("%c", Inquiry->ProductRevisionLevel[i]);
170 /* check the attached-media-changer bit... */
171 printf("Attached Changer: Yes\n");
175 printf("Attached Changer: No\n");
178 /* Now see if we have a bar code flag: */
179 if (Inquiry->AdditionalLength > 50)
181 /* see if we have 56 bytes: */
182 if (Inquiry->VendorFlags & 1)
184 printf("Bar Code Reader: Yes\n");
188 printf("Bar Code Reader: No\n");
192 free(Inquiry); /* well, we're about to exit, but ... */
195 /*********** MODE SENSE *******************/
196 /* We need 3 different mode sense pages. This is a generic
197 * routine for obtaining mode sense pages.
201 *mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense)
204 unsigned char *input_buffer; /*the input buffer -- has junk prepended to
208 unsigned char *retval; /* the return value. */
213 FatalError("mode_sense(6) can only read up to 255 characters!\n");
216 input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */
218 /* clear the sense buffer: */
219 slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
221 /* returns an array of bytes in the page, or, if not possible, NULL. */
222 CDB[0] = 0x1a; /* Mode Sense(6) */
224 CDB[2] = pagenum; /* the page to read. */
226 CDB[4] = 255; /* allocation length. This does max of 256 bytes! */
229 if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,
230 input_buffer, 255, RequestSense) != 0)
232 #ifdef DEBUG_MODE_SENSE
233 fprintf(stderr,"Could not execute mode sense...\n");
236 return NULL; /* sorry, couldn't do it. */
239 /* First skip past any header.... */
240 tmp = input_buffer + 4 + input_buffer[3];
241 /* now find out real length of page... */
243 retval = xmalloc(pagelen);
244 /* and copy our data to the new page. */
245 for (i = 0; i < pagelen; i++)
249 /* okay, free our input buffer: */
254 /* Report the Element Address Assignment Page */
255 static void ReportEAAP(DEVICE_TYPE MediumChangerFD)
258 RequestSense_T RequestSense;
260 EAAP = (EAAP_Type *)mode_sense(MediumChangerFD, 0x1d, sizeof(EAAP_Type), &RequestSense);
264 PrintRequestSense(&RequestSense);
265 printf("EAAP: No\n");
269 /* we did get an EAAP, so do our thing: */
270 printf("EAAP: Yes\n");
271 printf("Number of Medium Transport Elements: %d\n", ( ((unsigned int)EAAP->NumMediumTransportElements[0]<<8) + (unsigned int)EAAP->NumMediumTransportElements[1]));
272 printf("Number of Storage Elements: %d\n", ( ((unsigned int)EAAP->NumStorageElements[0]<<8) + (unsigned int)EAAP->NumStorageElements[1]));
273 printf("Number of Import/Export Elements: %d\n", ( ((unsigned int)EAAP->NumImportExportElements[0]<<8) + (unsigned int)EAAP->NumImportExportElements[1]));
274 printf("Number of Data Transfer Elements: %d\n", ( ((unsigned int)EAAP->NumDataTransferElements[0]<<8) + (unsigned int)EAAP->NumDataTransferElements[1]));
279 /* See if we can get some invert information: */
281 static void Report_TGDP(DEVICE_TYPE MediumChangerFD)
285 RequestSense_T RequestSense;
287 result=(TGDP_Type *)mode_sense(MediumChangerFD,0x1e,255,&RequestSense);
291 printf("Transport Geometry Descriptor Page: No\n");
295 printf("Transport Geometry Descriptor Page: Yes\n");
297 /* Now print out the invert bit: */
298 if ( result->Rotate & 1 )
300 printf("Invertable: Yes\n");
304 printf("Invertable: No\n");
310 /* Okay, let's get the Device Capabilities Page. We don't care
311 * about much here, just whether 'mtx transfer' will work (i.e.,
315 void TransferExchangeTargets(unsigned char ucValue, char *szPrefix)
317 if (ucValue & DT_BIT)
319 printf("%sData Transfer", szPrefix);
322 if (ucValue & IE_BIT)
324 printf("%s%sImport/Export", ucValue > (IE_BIT | (IE_BIT - 1)) ? ", " : "", szPrefix);
327 if (ucValue & ST_BIT)
329 printf("%s%sStorage", ucValue > (ST_BIT | (ST_BIT - 1)) ? ", " : "", szPrefix);
332 if (ucValue & MT_BIT)
334 printf("%s%sMedium Transfer", ucValue > (MT_BIT | (MT_BIT - 1)) ? ", " : "", szPrefix);
338 static void Report_DCP(DEVICE_TYPE MediumChangerFD)
341 RequestSense_T RequestSense;
344 result=(DCP_Type *)mode_sense(MediumChangerFD,0x1f,sizeof(DCP_Type),&RequestSense);
347 printf("Device Configuration Page: No\n");
351 printf("Device Configuration Page: Yes\n");
355 if (result->CanStore & DT_BIT)
357 printf("Data Transfer");
360 if (result->CanStore & IE_BIT)
362 printf("%sImport/Export", result->CanStore > (IE_BIT | (IE_BIT - 1)) ? ", " : "");
365 if (result->CanStore & ST_BIT)
367 printf("%sStorage", result->CanStore > (ST_BIT | (ST_BIT - 1)) ? ", " : "");
370 if (result->CanStore & MT_BIT)
372 printf("%sMedium Transfer", result->CanStore > (MT_BIT | (MT_BIT - 1)) ? ", " : "");
377 printf("SCSI Media Changer (rev 2): ");
379 if (result->SMC2_Caps & 0x01)
383 printf("Volume Tag Reader Present: %s\n", result->SMC2_Caps & 0x02 ? "Yes" : "No");
384 printf("Auto-Clean Enabled: %s\n", result->SMC2_Caps & 0x04 ? "Yes" : "No");
391 printf("Transfer Medium Transport: ");
392 if ((result->MT_Transfer & 0x0F) != 0)
394 TransferExchangeTargets(result->MT_Transfer, "->");
401 printf("\nTransfer Storage: ");
402 if ((result->ST_Transfer & 0x0F) != 0)
404 TransferExchangeTargets(result->ST_Transfer, "->");
411 printf("\nTransfer Import/Export: ");
412 if ((result->IE_Transfer & 0x0F) != 0)
414 TransferExchangeTargets(result->IE_Transfer, "->");
421 printf("\nTransfer Data Transfer: ");
422 if ((result->DT_Transfer & 0x0F) != 0)
424 TransferExchangeTargets(result->DT_Transfer, "->");
431 printf("\nExchange Medium Transport: ");
432 if ((result->MT_Exchange & 0x0F) != 0)
434 TransferExchangeTargets(result->MT_Exchange, "<>");
441 printf("\nExchange Storage: ");
442 if ((result->ST_Exchange & 0x0F) != 0)
444 TransferExchangeTargets(result->ST_Exchange, "<>");
451 printf("\nExchange Import/Export: ");
452 if ((result->IE_Exchange & 0x0F) != 0)
454 TransferExchangeTargets(result->IE_Exchange, "<>");
461 printf("\nExchange Data Transfer: ");
462 if ((result->DT_Exchange & 0x0F) != 0)
464 TransferExchangeTargets(result->DT_Exchange, "<>");
478 FatalError("Usage: loaderinfo -f <generic-device>\n");
482 /* we only have one argument: "-f <device>". */
483 int main(int argc, char **argv)
491 fprintf(stderr,"argc=%d",argc);
495 if (strcmp(argv[1],"-f")!=0)
502 fd=SCSI_OpenDevice(filename);
504 /* Now to call the various routines: */