fix lintian issues
[debian/mtx] / loaderinfo.c
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'.
5  */
6
7 /* 
8 * $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
9 * $Revision: 193 $
10 */
11
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. 
19  *   DeviceType:
20  *    Manufacturer:
21  *    ProdID:  
22  *    ProdRevision:
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
25  * bit 0 of byte 55. 
26  *
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
30  * each drive:
31  *
32  *  Drive number
33  *  EXCEPT (with ASC and ASCQ), if there is a problem. 
34  *  SCSI address and LUN
35  *  Tape drive Serial number
36  *   
37  */
38
39 #include <stdio.h>
40 #include "mtx.h"
41 #include "mtxl.h"
42
43 DEVICE_TYPE MediumChangerFD;  /* historic purposes... */
44
45 char *argv0;
46
47 /* A table for printing out the peripheral device type as ASCII. */ 
48 static char *PeripheralDeviceType[32] =
49 {
50         "Disk Drive",
51         "Tape Drive",
52         "Printer",
53         "Processor",
54         "Write-once",
55         "CD-ROM",
56         "Scanner",
57         "Optical",
58         "Medium Changer",
59         "Communications",
60         "ASC IT8",
61         "ASC IT8",
62         "RAID Array",
63         "Enclosure Services",
64         "OCR/W",
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 */
80         "Unknown"    /* 0x1f */
81 };
82
83
84 /* okay, now for the structure of an Element Address Assignment Page:  */
85
86 typedef struct EAAP
87 {
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];
99 }       EAAP_Type;
100
101 /* okay, now for the structure of a transport geometry
102  * descriptor page:
103  */
104 typedef struct TGDP
105 {
106         unsigned char Page_Code;
107         unsigned char ParameterLength;
108         unsigned char Rotate;
109         unsigned char ElementNumber;  /* we don't care about this... */
110 }       TGDP_Type;
111
112
113 /* Structure of the Device Capabilities Page: */
114 typedef struct DCP 
115 {
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 */
130 }       DCP_Type;
131
132 #define MT_BIT 0x01
133 #define ST_BIT 0x02
134 #define IE_BIT 0x04
135 #define DT_BIT 0x08
136
137 /* Okay, now for the inquiry information: */
138
139 static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
140 {
141         RequestSense_T RequestSense;
142         Inquiry_T *Inquiry;
143         int i;
144
145         Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);
146         if (Inquiry == NULL) 
147         {
148                 PrintRequestSense(&RequestSense);
149                 FatalError("INQUIRY Command Failed\n");
150         }
151
152         printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
153
154         printf("Vendor ID: '");
155         for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
156                 printf("%c", Inquiry->VendorIdentification[i]);
157
158         printf("'\nProduct ID: '");
159         for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
160                 printf("%c", Inquiry->ProductIdentification[i]);
161
162         printf("'\nRevision: '");
163         for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
164                 printf("%c", Inquiry->ProductRevisionLevel[i]);
165
166         printf("'\n");
167
168         if (Inquiry->MChngr) 
169         {
170                 /* check the attached-media-changer bit... */
171                 printf("Attached Changer: Yes\n");
172         }
173         else
174         {
175                 printf("Attached Changer: No\n");
176         }
177
178         /* Now see if we have a bar code flag: */
179         if (Inquiry->AdditionalLength > 50) 
180         {
181                 /* see if we have 56 bytes: */
182                 if (Inquiry->VendorFlags & 1)
183                 {
184                         printf("Bar Code Reader: Yes\n");
185                 }
186                 else
187                 {
188                         printf("Bar Code Reader: No\n");
189                 }
190         }
191
192         free(Inquiry);          /* well, we're about to exit, but ... */
193 }
194
195 /*********** MODE SENSE *******************/
196 /* We need 3 different mode sense pages. This is a generic
197  * routine for obtaining mode sense pages. 
198  */
199
200 static unsigned char
201 *mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len,  RequestSense_T *RequestSense)
202 {
203         CDB_T CDB;
204         unsigned char *input_buffer;    /*the input buffer -- has junk prepended to
205                                                                          * actual sense page. 
206                                                                          */
207         unsigned char *tmp;
208         unsigned char *retval;                  /* the return value. */
209         int i,pagelen;
210
211         if (alloc_len > 255)
212         {
213                 FatalError("mode_sense(6) can only read up to 255 characters!\n");
214         }
215
216         input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */
217
218         /* clear the sense buffer: */
219         slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
220
221         /* returns an array of bytes in the page, or, if not possible, NULL. */
222         CDB[0] = 0x1a; /* Mode Sense(6) */
223         CDB[1] = 0x08; 
224         CDB[2] = pagenum; /* the page to read. */
225         CDB[3] = 0;
226         CDB[4] = 255; /* allocation length. This does max of 256 bytes! */
227         CDB[5] = 0;
228
229         if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,
230                                                         input_buffer, 255, RequestSense) != 0)
231         {
232 #ifdef DEBUG_MODE_SENSE
233                 fprintf(stderr,"Could not execute mode sense...\n");
234                 fflush(stderr);
235 #endif
236                 return NULL; /* sorry, couldn't do it. */
237         }
238
239         /* First skip past any header.... */
240         tmp = input_buffer + 4 + input_buffer[3];
241         /* now find out real length of page... */
242         pagelen=tmp[1] + 2;
243         retval = xmalloc(pagelen);
244         /* and copy our data to the new page. */
245         for (i = 0; i < pagelen; i++)
246         {
247                 retval[i] = tmp[i];
248         }
249         /* okay, free our input buffer: */
250         free(input_buffer);
251         return retval;
252 }
253
254 /* Report the Element Address Assignment Page */
255 static void ReportEAAP(DEVICE_TYPE MediumChangerFD)
256 {
257         EAAP_Type *EAAP; 
258         RequestSense_T RequestSense;
259
260         EAAP = (EAAP_Type *)mode_sense(MediumChangerFD, 0x1d, sizeof(EAAP_Type), &RequestSense);
261
262         if (EAAP == NULL)
263         {
264                 PrintRequestSense(&RequestSense);
265                 printf("EAAP: No\n");
266                 return;
267         }
268
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]));
275
276         free(EAAP);
277 }
278
279 /* See if we can get some invert information: */
280
281 static void Report_TGDP(DEVICE_TYPE MediumChangerFD)
282 {
283         TGDP_Type *result;
284
285         RequestSense_T RequestSense;
286
287         result=(TGDP_Type *)mode_sense(MediumChangerFD,0x1e,255,&RequestSense);
288
289         if (!result)
290         {
291                 printf("Transport Geometry Descriptor Page: No\n");
292                 return;
293         }
294
295         printf("Transport Geometry Descriptor Page: Yes\n");
296
297         /* Now print out the invert bit: */
298         if ( result->Rotate & 1 )
299         {
300                 printf("Invertable: Yes\n");
301         }
302         else
303         {
304                 printf("Invertable: No\n");
305         }
306
307         free(result);
308 }
309
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., 
312  * ST->ST).
313  */
314
315 void TransferExchangeTargets(unsigned char ucValue, char *szPrefix)
316 {
317         if (ucValue & DT_BIT)
318         {
319                 printf("%sData Transfer", szPrefix);
320         }
321
322         if (ucValue & IE_BIT)
323         {
324                 printf("%s%sImport/Export", ucValue > (IE_BIT | (IE_BIT - 1)) ? ", " : "", szPrefix);
325         }
326
327         if (ucValue & ST_BIT)
328         {
329                 printf("%s%sStorage", ucValue > (ST_BIT | (ST_BIT - 1)) ? ", " : "", szPrefix);
330         }
331
332         if (ucValue & MT_BIT)
333         {
334                 printf("%s%sMedium Transfer", ucValue  > (MT_BIT | (MT_BIT - 1)) ? ", " : "", szPrefix);
335         }
336 }
337
338 static void Report_DCP(DEVICE_TYPE MediumChangerFD)
339 {
340         DCP_Type *result;
341         RequestSense_T RequestSense;
342
343         /* Get the page. */
344         result=(DCP_Type *)mode_sense(MediumChangerFD,0x1f,sizeof(DCP_Type),&RequestSense);
345         if (!result) 
346         {
347                 printf("Device Configuration Page: No\n");
348                 return;
349         }
350
351         printf("Device Configuration Page: Yes\n");
352
353         printf("Storage: ");
354
355         if (result->CanStore & DT_BIT)
356         {
357                 printf("Data Transfer");
358         }
359
360         if (result->CanStore & IE_BIT)
361         {
362                 printf("%sImport/Export", result->CanStore > (IE_BIT | (IE_BIT - 1)) ? ", " : "");
363         }
364
365         if (result->CanStore & ST_BIT)
366         {
367                 printf("%sStorage", result->CanStore > (ST_BIT | (ST_BIT - 1)) ? ", " : "");
368         }
369
370         if (result->CanStore & MT_BIT)
371         {
372                 printf("%sMedium Transfer", result->CanStore > (MT_BIT | (MT_BIT - 1)) ? ", " : "");
373         }
374
375         printf("\n");
376
377         printf("SCSI Media Changer (rev 2): ");
378
379         if (result->SMC2_Caps & 0x01)
380         {
381                 printf("Yes\n");
382
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");
385         }
386         else
387         {
388                 printf("No\n");
389         }
390
391         printf("Transfer Medium Transport: ");
392         if ((result->MT_Transfer & 0x0F) != 0)
393         {
394                 TransferExchangeTargets(result->MT_Transfer, "->");
395         }
396         else
397         {
398                 printf("None");
399         }
400
401         printf("\nTransfer Storage: ");
402         if ((result->ST_Transfer & 0x0F) != 0)
403         {
404                 TransferExchangeTargets(result->ST_Transfer, "->");
405         }
406         else
407         {
408                 printf("None");
409         }
410
411         printf("\nTransfer Import/Export: ");
412         if ((result->IE_Transfer & 0x0F) != 0)
413         {
414                 TransferExchangeTargets(result->IE_Transfer, "->");
415         }
416         else
417         {
418                 printf("None");
419         }
420
421         printf("\nTransfer Data Transfer: ");
422         if ((result->DT_Transfer & 0x0F) != 0)
423         {
424                 TransferExchangeTargets(result->DT_Transfer, "->");
425         }
426         else
427         {
428                 printf("None");
429         }
430
431         printf("\nExchange Medium Transport: ");
432         if ((result->MT_Exchange & 0x0F) != 0)
433         {
434                 TransferExchangeTargets(result->MT_Exchange, "<>");
435         }
436         else
437         {
438                 printf("None");
439         }
440
441         printf("\nExchange Storage: ");
442         if ((result->ST_Exchange & 0x0F) != 0)
443         {
444                 TransferExchangeTargets(result->ST_Exchange, "<>");
445         }
446         else
447         {
448                 printf("None");
449         }
450
451         printf("\nExchange Import/Export: ");
452         if ((result->IE_Exchange & 0x0F) != 0)
453         {
454                 TransferExchangeTargets(result->IE_Exchange, "<>");
455         }
456         else
457         {
458                 printf("None");
459         }
460
461         printf("\nExchange Data Transfer: ");
462         if ((result->DT_Exchange & 0x0F) != 0)
463         {
464                 TransferExchangeTargets(result->DT_Exchange, "<>");
465         }
466         else
467         {
468                 printf("None");
469         }
470
471         printf("\n");
472
473         free(result);
474 }
475
476 void usage(void)
477 {
478         FatalError("Usage: loaderinfo -f <generic-device>\n");
479 }
480
481
482 /* we only have one argument: "-f <device>". */
483 int main(int argc, char **argv)
484 {
485         DEVICE_TYPE fd;
486         char *filename;
487
488         argv0=argv[0];
489         if (argc != 3)
490         {
491                 fprintf(stderr,"argc=%d",argc);
492                 usage();
493         }
494
495         if (strcmp(argv[1],"-f")!=0)
496         {
497                 usage();
498         }
499
500         filename=argv[2];
501
502         fd=SCSI_OpenDevice(filename);
503
504         /* Now to call the various routines: */
505         ReportInquiry(fd);
506         ReportEAAP(fd);
507         Report_TGDP(fd);
508         Report_DCP(fd);
509         exit(0);
510 }