Imported Upstream version 2.4.4p3
[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.1.2.14.4.3.2.3 2003/01/26 19:20:56 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.1.2.14.4.3.2.3 2003/01/26 19:20:56 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         SCSI_OpenDevice(DeviceFD);
253       Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
254       SCSI_CloseDevice(DeviceFD);
255       
256       if ( Result < 0)
257         {
258           switch (ds.scsi_bus_status)
259             {
260             case SC_GOOD_STATUS:
261               SINQ[0] = SC_COM_REQUEST_SENSE;
262               SINQ[1] = 0; 
263               SINQ[2] = 0;
264               SINQ[3] = 0;
265               SINQ[4] = 0x1D;
266               SINQ[5] = 0x80;
267               bcopy(SINQ, ds.scsi_cdb, 6);
268               ds.command_length = 6;
269               ds.buffer = RequestSenseBuf;
270               ds.data_length = RequestSenseLength;
271               
272               if (pDev[DeviceFD].devopen == 0)
273                 SCSI_OpenDevice(DeviceFD);
274               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
275               SCSI_CloseDevice(DeviceFD);
276               return(SCSI_OK);
277               break;
278             case SC_BUSY_STATUS:
279               return(SCSI_BUSY);
280               break;
281             case SC_CHECK_CONDITION:
282               SINQ[0] = SC_COM_REQUEST_SENSE;
283               SINQ[1] = 0; 
284               SINQ[2] = 0;
285               SINQ[3] = 0;
286               SINQ[4] = 0x1D;
287               SINQ[5] = 0x80;
288               bcopy(SINQ, ds.scsi_cdb, 6);
289               ds.command_length = 6;
290               ds.buffer = RequestSenseBuf;
291               ds.data_length = RequestSenseLength;
292
293               if (pDev[DeviceFD].devopen == 0)
294                 SCSI_OpenDevice(DeviceFD);
295               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
296               SCSI_CloseDevice(DeviceFD);
297               return(SCSI_CHECK);
298               break;
299             default:
300               /*
301                * Makes no sense yet, may result in an endless loop
302                *
303                RequestSense(DeviceFD, &ExtendedRequestSense, 0);
304                DecodeExtSense(&ExtendedRequestSense, "SCSI_ExecuteCommand:", debug_file);
305                bcopy(&ExtendedRequestSense, RequestSenseBuf, RequestSenseLength);
306               */
307               dbprintf(("ioctl on %d return %d\n", pDev[DeviceFD].fd, Result));
308               dbprintf(("ret: %d errno: %d (%s)\n", Result, errno, ""));
309               dbprintf(("data_length:     %d\n", ds.data_length));
310               dbprintf(("buffer:          0x%X\n", ds.buffer));
311               dbprintf(("timeout_value:   %d\n", ds.timeout_value));
312               dbprintf(("status_validity: %d\n", ds.status_validity));
313               dbprintf(("scsi_bus_status: 0x%X\n", ds.scsi_bus_status));
314               dbprintf(("adapter_status:  0x%X\n", ds.adapter_status));
315               dbprintf(("adap_q_status:   0x%X\n", ds.adap_q_status));
316               dbprintf(("q_tag_msg:       0x%X\n", ds.q_tag_msg));
317               dbprintf(("flags:           0X%X\n", ds.flags));
318               return(SCSI_ERROR);
319             }
320         }
321       return(SCSI_OK);
322     }
323 }
324
325 int SCSI_Scan()
326 {
327   int fd;
328   extern int errno;
329   struct sc_inquiry si;
330   u_char buf[255];
331   int target;
332   int lun;
333   int isbusy;
334   char type;
335   char bus[] = "/dev/scsi0";
336   
337   if ((fd = open(bus, O_RDWR)) == -1)
338     return(1);
339
340   for (target = 0; target < 7; target++) 
341     {
342       for (lun = 0; lun < 7; lun++)
343         {
344           printf("Target:Lun %d:%d\n", target,lun);
345           if (ioctl(fd, SCIOSTART, IDLUN(target, lun)) == -1) {
346             if (errno == EINVAL) {
347               printf("is in use\n");
348               isbusy = 1;
349             } else {
350               return(1);
351             }
352           } else {
353             isbusy = 0;
354           }
355           
356           bzero(&si, sizeof(si));
357           si.scsi_id = target;
358           si.lun_id = lun;
359           si.inquiry_len = 255;
360           si.inquiry_ptr = (char *)&buf;
361           if (ioctl(fd, SCIOINQU, &si) == -1)
362             {
363               printf("SCIOINQU: %s\n", strerror(errno));
364             } else {
365               dump_hex(&buf, 255, DEBUG_INFO, SECTION_SCSI);
366               type = buf[0] & 0x1f;
367               buf[8+28] = 0;
368               printf(stdout,"%-28s|Device Type %d\n",buf[8], type);
369             }
370           if (!isbusy && ioctl(fd, SCIOSTOP, IDLUN(target, lun)) == -1)
371             return(1);
372         }
373     }
374 }
375
376 int Tape_Ioctl(int DeviceFD, int command)
377 {
378   extern OpenFiles_T *pDev;
379   int ret = -1;
380   return(ret);
381 }
382
383 int Tape_Status( int DeviceFD)
384 {
385 /*
386   Not yet
387 */
388   return(-1);
389 }
390
391 int ScanBus(int print)
392 {
393 /*
394   Not yet
395 */
396   SCSI_Scan();
397   return(-1);
398 }
399
400 #endif
401 /*
402  * Local variables:
403  * indent-tabs-mode: nil
404  * c-file-style: gnu
405  * End:
406  */