Imported Upstream version 1.2.16rel
[debian/mtx] / loaderinfo.c
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  */
5
6 /* 
7 * $Date: 2001/06/05 17:10:21 $
8 * $Revision: 1.1.1.1 $
9 */
10
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. 
18  *   DeviceType:
19  *    Manufacturer:
20  *    ProdID:  
21  *    ProdRevision:
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
24  * bit 0 of byte 55. 
25  *
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
29  * each drive:
30  *
31  *  Drive number
32  *  EXCEPT (with ASC and ASCQ), if there is a problem. 
33  *  SCSI address and LUN
34  *  Tape drive Serial number
35  *   
36  */
37
38 #include <stdio.h>
39 #include "mtx.h"
40 #include "mtxl.h"
41
42 DEVICE_TYPE MediumChangerFD;  /* historic purposes... */
43
44 char *argv0;
45
46 /* A table for printing out the peripheral device type as ASCII. */ 
47 static char *PeripheralDeviceType[32] = {
48   "Disk Drive",
49   "Tape Drive",
50   "Printer",
51   "Processor",
52   "Write-once",
53   "CD-ROM",
54   "Scanner",
55   "Optical",
56   "Medium Changer",
57   "Communications",
58   "ASC IT8",
59   "ASC IT8",
60   "RAID Array",
61   "Enclosure Services",
62   "OCR/W",
63   "Bridging Expander", /* 0x10 */
64   "Reserved",  /* 0x11 */
65   "Reserved", /* 0x12 */
66   "Reserved",  /* 0x13 */
67   "Reserved",  /* 0x14 */
68   "Reserved",  /* 0x15 */
69   "Reserved",  /* 0x16 */
70   "Reserved",  /* 0x17 */
71   "Reserved",  /* 0x18 */
72   "Reserved",  /* 0x19 */
73   "Reserved",  /* 0x1a */
74   "Reserved",  /* 0x1b */
75   "Reserved",  /* 0x1c */
76   "Reserved",  /* 0x1d */
77   "Reserved",  /* 0x1e */
78   "Unknown"    /* 0x1f */
79 };
80
81
82 /* okay, now for the structure of an Element Address Assignment Page:  */
83
84 typedef struct EAAP {
85   unsigned char Page_Code;
86   unsigned char Parameter_Length;
87   unsigned char MediumTransportElementAddress[2];
88   unsigned char NumMediumTransportElements[2];
89   unsigned char FirstStorageElementAdddress[2];
90   unsigned char NumStorageElements[2];
91   unsigned char FirstImportExportElementAddress[2];
92   unsigned char NumImportExportElements[2];
93   unsigned char FirstDataTransferElementAddress[2];
94   unsigned char NumDataTransferElements[2];
95   unsigned char Reserved[2];
96 } EAAP_Type;
97
98 /* okay, now for the structure of a transport geometry
99  * descriptor page:
100  */
101 typedef struct TGDP {
102   unsigned char Page_Code;
103   unsigned char ParameterLength;
104   unsigned char Rotate;
105   unsigned char ElementNumber;  /* we don't care about this... */
106 } TGDP_Type;
107
108
109 /* Structure of the Device Capabilities Page: */
110 typedef struct DCP {
111   unsigned char Page_Code;
112   unsigned char ParameterLength;
113   unsigned char CanStore;  /* bits about whether elements can store carts */
114   unsigned char Reserved; 
115   unsigned char MT_Xfer;  /* bits about whether mt->xx xfers work. */
116   unsigned char ST_Xfer;  /* bits about whether st->xx xfers work. */
117   unsigned char IE_Xfer;  /* bits about whether id->xx xfers work. */
118   unsigned char DT_Xfer; /* bits about whether DT->xx xfers work. */
119   unsigned char Reserved2[12];  /* more reserved data */
120 } DCP_Type ; 
121
122 #define MT_BIT 0x01
123 #define ST_BIT 0x02
124 #define IE_BIT 0x04
125 #define DT_BIT 0x08
126
127 /* Okay, now for the inquiry information: */
128
129 static void ReportInquiry(DEVICE_TYPE MediumChangerFD)
130 {
131   RequestSense_T RequestSense;
132   Inquiry_T *Inquiry;
133   int i;
134
135   Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);
136   if (Inquiry == NULL) 
137     {
138       PrintRequestSense(&RequestSense);
139       FatalError("INQUIRY Command Failed\n");
140     }
141   
142   printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]);
143   printf("Vendor ID: '");
144   for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)
145     printf("%c", Inquiry->VendorIdentification[i]);
146   printf("'\nProduct ID: '");
147   for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)
148     printf("%c", Inquiry->ProductIdentification[i]);
149   printf("'\nRevision: '");
150   for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)
151     printf("%c", Inquiry->ProductRevisionLevel[i]);
152   printf("'\n");\
153   if (Inquiry->MChngr) {  /* check the attached-media-changer bit... */
154     printf("Attached Changer: Yes\n");
155   } else {
156     printf("Attached Changer: No\n");
157   }
158   /* Now see if we have a bar code flag: */
159   if (Inquiry->AdditionalLength > 50) {  /* see if we have 56 bytes: */
160     if (Inquiry->VendorFlags & 1) {
161       printf("Bar Code Reader: Yes\n");
162     } else {
163       printf("Bar Code Reader: No\n");
164     }
165   }
166   
167   free(Inquiry);  /* well, we're about to exit, but ... */
168   return; /* done! */
169 }
170
171 /*********** MODE SENSE *******************/
172 /* We need 3 different mode sense pages. This is a generic
173  * routine for obtaining mode sense pages. 
174  */
175
176 static unsigned char
177 *mode_sense(DEVICE_TYPE fd, int pagenum, int alloc_len,  RequestSense_T *RequestSense) {
178   CDB_T CDB;
179   unsigned char *input_buffer; /*the input buffer -- has junk prepended to
180                                 * actual sense page. 
181                                 */
182   unsigned char *tmp;
183   unsigned char *retval;  /* the return value. */
184   int i,pagelen;
185
186   if (alloc_len > 255) {
187     FatalError("mode_sense(6) can only read up to 255 characters!\n");
188   }
189
190   input_buffer=(unsigned char *)xzmalloc(256); /* overdo it, eh? */
191
192   /* clear the sense buffer: */
193   slow_bzero((char *)RequestSense,sizeof(RequestSense_T));
194   
195
196   /* returns an array of bytes in the page, or, if not possible, NULL. */
197   CDB[0]=0x1a; /* Mode Sense(6) */
198   CDB[1]=0; 
199   CDB[2]=pagenum; /* the page to read. */
200   CDB[3]=0;
201   CDB[4]=255; /* allocation length. This does max of 256 bytes! */
202   CDB[5]=0;
203   
204   if (SCSI_ExecuteCommand(fd,Input,&CDB,6,
205                           input_buffer,255,RequestSense) != 0) {
206 #ifdef DEBUG_MODE_SENSE
207     fprintf(stderr,"Could not execute mode sense...\n");
208     fflush(stderr);
209 #endif
210     return NULL; /* sorry, couldn't do it. */
211   }
212   
213   /* First skip past any header.... */
214   tmp=input_buffer+4+input_buffer[3];
215   /* now find out real length of page... */
216   pagelen=tmp[1]+2;
217   retval=xmalloc(pagelen);
218   /* and copy our data to the new page. */
219   for (i=0;i<pagelen;i++) {
220     retval[i]=tmp[i];
221   }
222   /* okay, free our input buffer: */
223   free(input_buffer);
224   return retval;
225 }
226
227 /* Report the Element Address Assignment Page */
228 static EAAP_Type *ReportEAAP(DEVICE_TYPE MediumChangerFD) {
229   EAAP_Type *EAAP; 
230   RequestSense_T RequestSense;
231
232   EAAP=(EAAP_Type *)mode_sense(MediumChangerFD,0x1d,sizeof(EAAP_Type),&RequestSense);
233   
234   if (EAAP==NULL) {
235     printf("EAAP: No\n");
236     return NULL;
237   }
238
239   /* we did get an EAAP, so do our thing: */
240   printf("EAAP: Yes\n");
241   printf("Number of Medium Transport Elements: %d\n", ( ((unsigned int)EAAP->NumMediumTransportElements[0]<<8) + (unsigned int)EAAP->NumMediumTransportElements[1]));
242   printf("Number of Storage Elements: %d\n", ( ((unsigned int)EAAP->NumStorageElements[0]<<8) + (unsigned int)EAAP->NumStorageElements[1]));
243   printf("Number of Import/Export Element Elements: %d\n", ( ((unsigned int)EAAP->NumImportExportElements[0]<<8) + (unsigned int)EAAP->NumImportExportElements[1]));
244   printf("Number of Data Transfer Elements: %d\n", ( ((unsigned int)EAAP->NumDataTransferElements[0]<<8) + (unsigned int)EAAP->NumDataTransferElements[1]));
245   
246   return EAAP;
247 }
248
249 /* See if we can get some invert information: */
250
251 static void Report_TGDP(DEVICE_TYPE MediumChangerFD) {
252   TGDP_Type *result;
253   
254   RequestSense_T RequestSense;
255
256   result=(TGDP_Type *)mode_sense(MediumChangerFD,0x1e,255,&RequestSense);
257   
258   if (!result) {
259     printf("Transport Geometry Descriptor Page: No\n");
260     return;
261   }
262
263   printf("Transport Geometry Descriptor Page: Yes\n");
264   
265   /* Now print out the invert bit: */
266   if ( result->Rotate & 1 ) {
267     printf("Invertable: Yes\n");
268   } else {
269     printf("Invertable: No\n");
270   }
271
272   return;  /* done. */
273 }
274
275 /* Okay, let's get the Device Capabilities Page. We don't care
276  * about much here, just whether 'mtx transfer' will work (i.e., 
277  * ST->ST).
278  */
279
280 static void Report_DCP(DEVICE_TYPE MediumChangerFD) {
281   DCP_Type *result;
282   RequestSense_T RequestSense;
283
284   /* Get the page. */
285   result=(DCP_Type *)mode_sense(MediumChangerFD,0x1f,sizeof(DCP_Type),&RequestSense);
286   if (!result) {
287     printf("Device Configuration Page: No\n");
288     return;
289   }
290   
291   printf("Device Configuration Page: Yes\n");
292
293   /* okay, now see if we can do xfers: */
294   if (result->ST_Xfer & ST_BIT) {
295     printf("Can Transfer: Yes\n");
296   } else {
297     printf("Can Transfer: No\n");
298   }
299   /* We don't care about anything else at the moment, eventually we
300    * do want to add the inport/export stuff here too...
301    */
302
303   return;
304 }
305
306 void usage(void) {
307   FatalError("Usage: loaderinfo -f <generic-device>\n");
308 }
309
310
311 /* we only have one argument: "-f <device>". */
312 int main(int argc, char **argv) {
313   DEVICE_TYPE fd;
314   char *filename;
315
316   argv0=argv[0];
317   if (argc != 3) {
318     fprintf(stderr,"argc=%d",argc);
319     usage();
320   }
321
322   if (strcmp(argv[1],"-f")!=0) {
323     usage();
324   }
325   filename=argv[2];
326   
327   fd=SCSI_OpenDevice(filename);
328   
329   /* Now to call the various routines: */
330   ReportInquiry(fd);
331   ReportEAAP(fd);
332   Report_TGDP(fd);
333   Report_DCP(fd);
334   exit(0);
335 }