4696faf693c66d571d76a4b7a2adbd4aecf2a547
[debian/amanda] / changer-src / scsi-aix.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: scsi-aix.c,v 1.22 2005/10/15 13:20:47 martinea Exp $
28  *
29  * Interface to execute SCSI commands on an AIX System
30  *
31  * Copyright (c) Thomas Hepper th@ant.han.de
32  */
33
34
35 #include <amanda.h>
36
37 #ifdef HAVE_AIX_LIKE_SCSI
38
39 #ifdef HAVE_SYS_TYPES_H
40 #include <sys/types.h>
41 #endif
42 #ifdef HAVE_STAT_H
43 #include <sys/stat.h>
44 #endif
45 #ifdef HAVE_FCNTL_H
46 #include <fcntl.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #ifdef HAVE_STDIO_H
52 #include <stdio.h>
53 #endif
54 #ifdef HAVE_ERRNO_H
55 #include <errno.h>
56 #endif
57
58 #include <sys/scarray.h>
59 #include <sys/tape.h>
60
61 #include <scsi-defs.h>
62 #include <gscdds.h>
63
64 void SCSI_OS_Version()
65 {
66 #ifndef lint
67    static char rcsid[] = "$Id: scsi-aix.c,v 1.22 2005/10/15 13:20:47 martinea Exp $";
68    DebugPrint(DEBUG_INFO, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
69 #endif
70 }
71
72
73 int SCSI_OpenDevice(int ip)
74 {
75   int DeviceFD;
76   int i;
77   extern OpenFiles_T *pDev;
78   
79   if (pDev[ip].inqdone == 0)
80     {
81       pDev[ip].inqdone = 1;
82       /*
83        * Check if it is an gsc (generic SCSI device)
84        */
85       if (strncmp("/dev/gsc", pDev[ip].dev, 8) == 0)
86         {
87           pDev[ip].flags = AIX_USE_GSC;
88           DeviceFD = open(pDev[ip].dev, 0);
89         } else {
90           DeviceFD = openx(pDev[ip].dev, O_RDWR, 0, SC_DIAGNOSTIC);
91         }
92       if (DeviceFD >= 0)
93         {
94           pDev[ip].avail = 1;
95           pDev[ip].fd = DeviceFD;
96           pDev[ip].SCSI = 0;
97           pDev[ip].devopen = 1;
98           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
99
100           if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0)
101             {
102              if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
103                {
104                  for (i=0;i < 16;i++)
105                    pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
106                  for (i=15; i >= 0 && !isalnum(pDev[ip].ident[i]) ; i--)
107                    {
108                      pDev[ip].ident[i] = '\0';
109                    }
110                  pDev[ip].SCSI = 1;
111
112                   if (pDev[ip].inquiry->type == TYPE_TAPE)
113                   {
114                           pDev[ip].type = stralloc("tape");
115                   }
116
117                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
118                   {
119                           pDev[ip].type = stralloc("changer");
120                   }
121
122                  PrintInquiry(pDev[ip].inquiry);
123                  return(1); 
124                } else {
125                  close(DeviceFD);
126                  free(pDev[ip].inquiry);
127                  return(0);
128                }
129            } else {
130              free(pDev[ip].inquiry);
131              pDev[ip].inquiry = NULL;
132              return(1);
133            }
134          return(1);
135        } else {
136          dbprintf(("SCSI_OpenDevice %s failed\n", pDev[ip].dev));
137          return(0);
138        }
139     } else {
140       if ((DeviceFD = openx(pDev[ip].dev, O_RDWR, 0, SC_DIAGNOSTIC)) >= 0)
141         {
142           pDev[ip].fd = DeviceFD;
143           pDev[ip].devopen = 1;
144           return(1);
145         }
146     }
147   return(0);
148 }
149
150 int SCSI_CloseDevice(int DeviceFD)
151 {
152   int ret;
153   extern OpenFiles_T *pDev;
154
155   ret = close(pDev[DeviceFD].fd);
156   pDev[DeviceFD].devopen = 0;
157   return(ret);
158
159 }
160
161 int SCSI_ExecuteCommand(int DeviceFD,
162                         Direction_T Direction,
163                         CDB_T CDB,
164                         int CDB_Length,
165                         void *DataBuffer,
166                         int DataBufferLength,
167                         char *RequestSenseBuf,
168                         int RequestSenseLength)
169 {
170   extern OpenFiles_T *pDev;
171   extern FILE * debug_file;
172   CDB_T CDBSENSE;
173   CDB_T SINQ;
174   ExtendedRequestSense_T ExtendedRequestSense;
175   struct sc_iocmd ds;
176   scmd_t scmd;
177   char sbyte;
178   int Result;
179   int isbusy = 0;
180   int target = 3;
181
182
183   if (pDev[DeviceFD].avail == 0)
184     {
185       return(SCSI_ERROR);
186     }
187
188
189   if (pDev[DeviceFD].flags == AIX_USE_GSC)
190     {
191       scmd.cdb = CDB;
192       scmd.cdblen = CDB_Length;
193       scmd.data_buf = DataBuffer;
194       scmd.datalen = DataBufferLength;
195       scmd.sense_buf = RequestSenseBuf;
196       scmd.senselen = RequestSenseLength;
197       scmd.statusp = &sbyte;
198       scmd.timeval = 60;
199       switch (Direction) 
200         {
201         case Input:
202           scmd.rw = 0;
203           break;
204         case Output:
205           scmd.rw = 1;
206           break;
207         }
208
209       if (ioctl(pDev[DeviceFD].fd, GSC_CMD, (caddr_t) &scmd) < 0) {
210         return(SCSI_ERROR);
211       }
212       return(SCSI_OK);
213
214     } else {
215       bzero(&ds, sizeof(struct sc_iocmd));
216       bzero(RequestSenseBuf, RequestSenseLength);
217       bzero(&ExtendedRequestSense, sizeof(ExtendedRequestSense_T));
218       
219       ds.flags = SC_ASYNC; 
220       /* Timeout */
221       ds.timeout_value = 60;
222       bcopy(CDB, ds.scsi_cdb, CDB_Length);
223       ds.command_length = CDB_Length;
224       /* 
225        *  Data buffer for results 
226        * If the size of the buffer is 0
227        * then keep this fields untouched           
228        */
229       if (DataBufferLength > 0)
230         {
231           ds.buffer = DataBuffer;
232           ds.data_length = DataBufferLength;
233         }
234       
235       /* Sense Buffer is not available on AIX ?*/
236       /*
237         ds.req_sense_length = 255;
238         ds.request_sense_ptr = (char *)RequestSense;
239       */
240       switch (Direction) 
241         {
242         case Input:
243           ds.flags = ds.flags | B_READ;
244           break;
245         case Output:
246           ds.flags = ds.flags | B_WRITE;
247           break;
248         }
249       DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
250       
251       if (pDev[DeviceFD].devopen == 0)
252         if (SCSI_OpenDevice(DeviceFD) == 0)
253           return(SCSI_ERROR);
254       Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
255       SCSI_CloseDevice(DeviceFD);
256       
257       if ( Result < 0)
258         {
259           switch (ds.scsi_bus_status)
260             {
261             case SC_GOOD_STATUS:
262               SINQ[0] = SC_COM_REQUEST_SENSE;
263               SINQ[1] = 0; 
264               SINQ[2] = 0;
265               SINQ[3] = 0;
266               SINQ[4] = 0x1D;
267               SINQ[5] = 0x80;
268               bcopy(SINQ, ds.scsi_cdb, 6);
269               ds.command_length = 6;
270               ds.buffer = RequestSenseBuf;
271               ds.data_length = RequestSenseLength;
272               
273               if (pDev[DeviceFD].devopen == 0)
274                 if (SCSI_OpenDevice(DeviceFD) == 0)
275                   return(SCSI_ERROR);
276               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
277               SCSI_CloseDevice(DeviceFD);
278               return(SCSI_OK);
279               break;
280             case SC_BUSY_STATUS:
281               return(SCSI_BUSY);
282               break;
283             case SC_CHECK_CONDITION:
284               SINQ[0] = SC_COM_REQUEST_SENSE;
285               SINQ[1] = 0; 
286               SINQ[2] = 0;
287               SINQ[3] = 0;
288               SINQ[4] = 0x1D;
289               SINQ[5] = 0x80;
290               bcopy(SINQ, ds.scsi_cdb, 6);
291               ds.command_length = 6;
292               ds.buffer = RequestSenseBuf;
293               ds.data_length = RequestSenseLength;
294
295               if (pDev[DeviceFD].devopen == 0)
296                 if (SCSI_OpenDevice(DeviceFD) == 0)
297                   return(SCSI_ERROR);
298               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
299               SCSI_CloseDevice(DeviceFD);
300               return(SCSI_CHECK);
301               break;
302             default:
303               /*
304                * Makes no sense yet, may result in an endless loop
305                *
306                RequestSense(DeviceFD, &ExtendedRequestSense, 0);
307                DecodeExtSense(&ExtendedRequestSense, "SCSI_ExecuteCommand:", debug_file);
308                bcopy(&ExtendedRequestSense, RequestSenseBuf, RequestSenseLength);
309               */
310               dbprintf(("ioctl on %d return %d\n", pDev[DeviceFD].fd, Result));
311               dbprintf(("ret: %d errno: %d (%s)\n", Result, errno, ""));
312               dbprintf(("data_length:     %d\n", ds.data_length));
313               dbprintf(("buffer:          0x%X\n", ds.buffer));
314               dbprintf(("timeout_value:   %d\n", ds.timeout_value));
315               dbprintf(("status_validity: %d\n", ds.status_validity));
316               dbprintf(("scsi_bus_status: 0x%X\n", ds.scsi_bus_status));
317               dbprintf(("adapter_status:  0x%X\n", ds.adapter_status));
318               dbprintf(("adap_q_status:   0x%X\n", ds.adap_q_status));
319               dbprintf(("q_tag_msg:       0x%X\n", ds.q_tag_msg));
320               dbprintf(("flags:           0X%X\n", ds.flags));
321               return(SCSI_ERROR);
322             }
323         }
324       return(SCSI_OK);
325     }
326 }
327
328 int SCSI_Scan()
329 {
330   int fd;
331   extern int errno;
332   struct sc_inquiry si;
333   u_char buf[255];
334   int target;
335   int lun;
336   int isbusy;
337   char type;
338   char bus[] = "/dev/scsi0";
339   
340   if ((fd = open(bus, O_RDWR)) == -1)
341     return(1);
342
343   for (target = 0; target < 7; target++) 
344     {
345       for (lun = 0; lun < 7; lun++)
346         {
347           printf("Target:Lun %d:%d\n", target,lun);
348           if (ioctl(fd, SCIOSTART, IDLUN(target, lun)) == -1) {
349             if (errno == EINVAL) {
350               printf("is in use\n");
351               isbusy = 1;
352             } else {
353               return(1);
354             }
355           } else {
356             isbusy = 0;
357           }
358           
359           bzero(&si, sizeof(si));
360           si.scsi_id = target;
361           si.lun_id = lun;
362           si.inquiry_len = 255;
363           si.inquiry_ptr = (char *)&buf;
364           if (ioctl(fd, SCIOINQU, &si) == -1)
365             {
366               printf("SCIOINQU: %s\n", strerror(errno));
367             } else {
368               dump_hex(&buf, 255, DEBUG_INFO, SECTION_SCSI);
369               type = buf[0] & 0x1f;
370               buf[8+28] = 0;
371               printf(stdout,"%-28s|Device Type %d\n",buf[8], type);
372             }
373           if (!isbusy && ioctl(fd, SCIOSTOP, IDLUN(target, lun)) == -1)
374             return(1);
375         }
376     }
377 }
378
379 int Tape_Ioctl(int DeviceFD, int command)
380 {
381   extern OpenFiles_T *pDev;
382   int ret = -1;
383   return(ret);
384 }
385
386 int Tape_Status( int DeviceFD)
387 {
388 /*
389   Not yet
390 */
391   return(-1);
392 }
393
394 int ScanBus(int print)
395 {
396 /*
397   Not yet
398 */
399   SCSI_Scan();
400   return(-1);
401 }
402
403 #endif
404 /*
405  * Local variables:
406  * indent-tabs-mode: nil
407  * c-file-style: gnu
408  * End:
409  */