Imported Upstream version 2.5.1
[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.23 2006/05/25 01:47:07 johnfranks 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 #include <scsi-defs.h>
40
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h>
43 #endif
44 #ifdef HAVE_STAT_H
45 #include <sys/stat.h>
46 #endif
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #ifdef HAVE_STDIO_H
54 #include <stdio.h>
55 #endif
56 #ifdef HAVE_ERRNO_H
57 #include <errno.h>
58 #endif
59
60 #include <sys/scarray.h>
61 #include <sys/tape.h>
62
63 #include <scsi-defs.h>
64 #include <gscdds.h>
65
66 void SCSI_OS_Version(void)
67 {
68 #ifndef lint
69    static char rcsid[] = "$Id: scsi-aix.c,v 1.23 2006/05/25 01:47:07 johnfranks Exp $";
70    DebugPrint(DEBUG_INFO, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
71 #endif
72 }
73
74
75 int SCSI_OpenDevice(int ip)
76 {
77   int DeviceFD;
78   int i;
79   extern OpenFiles_T *pDev;
80   
81   if (pDev[ip].inqdone == 0)
82     {
83       pDev[ip].inqdone = 1;
84       /*
85        * Check if it is an gsc (generic SCSI device)
86        */
87       if (strncmp("/dev/gsc", pDev[ip].dev, 8) == 0)
88         {
89           pDev[ip].flags = AIX_USE_GSC;
90           DeviceFD = open(pDev[ip].dev, 0);
91         } else {
92           DeviceFD = openx(pDev[ip].dev, O_RDWR, 0, SC_DIAGNOSTIC);
93         }
94       if (DeviceFD >= 0)
95         {
96           pDev[ip].avail = 1;
97           pDev[ip].fd = DeviceFD;
98           pDev[ip].SCSI = 0;
99           pDev[ip].devopen = 1;
100           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
101
102           if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0)
103             {
104              if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
105                {
106                  for (i=0;i < 16;i++)
107                    pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
108                  for (i=15; i >= 0 && !isalnum(pDev[ip].ident[i]) ; i--)
109                    {
110                      pDev[ip].ident[i] = '\0';
111                    }
112                  pDev[ip].SCSI = 1;
113
114                   if (pDev[ip].inquiry->type == TYPE_TAPE)
115                   {
116                           pDev[ip].type = stralloc("tape");
117                   }
118
119                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
120                   {
121                           pDev[ip].type = stralloc("changer");
122                   }
123
124                  PrintInquiry(pDev[ip].inquiry);
125                  return(1); 
126                } else {
127                  close(DeviceFD);
128                  free(pDev[ip].inquiry);
129                  return(0);
130                }
131            }
132            free(pDev[ip].inquiry);
133            pDev[ip].inquiry = NULL;
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                         size_t CDB_Length,
165                         void *DataBuffer,
166                         size_t DataBufferLength,
167                         RequestSense_T *RequestSenseBuf,
168                         size_t 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   /* Basic sanity checks */
183   assert(CDB_Length <= UCHAR_MAX);
184   assert(RequestSenseLength <= UCHAR_MAX);
185
186   /* Clear buffer for cases where sense is not returned */
187   memset(RequestSenseBuf, 0, RequestSenseLength);
188
189   if (pDev[DeviceFD].avail == 0)
190     {
191       return(SCSI_ERROR);
192     }
193
194
195   if (pDev[DeviceFD].flags == AIX_USE_GSC)
196     {
197       scmd.cdb = CDB;
198       scmd.cdblen = CDB_Length;
199       scmd.data_buf = DataBuffer;
200       scmd.datalen = DataBufferLength;
201       scmd.sense_buf = (unsigned char *)RequestSenseBuf;
202       scmd.senselen = RequestSenseLength;
203       scmd.statusp = &sbyte;
204       scmd.timeval = 60;
205       switch (Direction) 
206         {
207         case Input:
208           scmd.rw = 0;
209           break;
210         case Output:
211           scmd.rw = 1;
212           break;
213         }
214
215       if (ioctl(pDev[DeviceFD].fd, GSC_CMD, (caddr_t) &scmd) < 0) {
216         return(SCSI_ERROR);
217       }
218       return(SCSI_OK);
219
220     } else {
221       bzero(&ds, SIZEOF(struct sc_iocmd));
222       bzero(RequestSenseBuf, RequestSenseLength);
223       bzero(&ExtendedRequestSense, SIZEOF(ExtendedRequestSense_T));
224       
225       ds.flags = SC_ASYNC; 
226       /* Timeout */
227       ds.timeout_value = 60;
228       bcopy(CDB, ds.scsi_cdb, CDB_Length);
229       ds.command_length = CDB_Length;
230       /* 
231        *  Data buffer for results 
232        * If the size of the buffer is 0
233        * then keep this fields untouched           
234        */
235       if (DataBufferLength > 0)
236         {
237           ds.buffer = DataBuffer;
238           ds.data_length = DataBufferLength;
239         }
240       
241       /* Sense Buffer is not available on AIX ?*/
242       /*
243         ds.req_sense_length = 255;
244         ds.request_sense_ptr = (unsigned char *)RequestSense;
245       */
246       switch (Direction) 
247         {
248         case Input:
249           ds.flags = ds.flags | B_READ;
250           break;
251         case Output:
252           ds.flags = ds.flags | B_WRITE;
253           break;
254         }
255       DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
256       
257       if (pDev[DeviceFD].devopen == 0)
258         if (SCSI_OpenDevice(DeviceFD) == 0)
259           return(SCSI_ERROR);
260       Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
261       SCSI_CloseDevice(DeviceFD);
262       
263       if ( Result < 0)
264         {
265           switch (ds.scsi_bus_status)
266             {
267             case SC_GOOD_STATUS:
268               SINQ[0] = SC_COM_REQUEST_SENSE;
269               SINQ[1] = 0; 
270               SINQ[2] = 0;
271               SINQ[3] = 0;
272               SINQ[4] = 0x1D;
273               SINQ[5] = 0x80;
274               bcopy(SINQ, ds.scsi_cdb, 6);
275               ds.command_length = 6;
276               ds.buffer = (unsigned char *)RequestSenseBuf;
277               ds.data_length = RequestSenseLength;
278               
279               if (pDev[DeviceFD].devopen == 0)
280                 if (SCSI_OpenDevice(DeviceFD) == 0)
281                   return(SCSI_ERROR);
282               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
283               SCSI_CloseDevice(DeviceFD);
284               return(SCSI_OK);
285
286             case SC_BUSY_STATUS:
287               return(SCSI_BUSY);
288
289             case SC_CHECK_CONDITION:
290               SINQ[0] = SC_COM_REQUEST_SENSE;
291               SINQ[1] = 0; 
292               SINQ[2] = 0;
293               SINQ[3] = 0;
294               SINQ[4] = 0x1D;
295               SINQ[5] = 0x80;
296               bcopy(SINQ, ds.scsi_cdb, 6);
297               ds.command_length = 6;
298               ds.buffer = (unsigned char *)RequestSenseBuf;
299               ds.data_length = (unsigned char)RequestSenseLength;
300
301               if (pDev[DeviceFD].devopen == 0)
302                 if (SCSI_OpenDevice(DeviceFD) == 0)
303                   return(SCSI_ERROR);
304               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
305               SCSI_CloseDevice(DeviceFD);
306               return(SCSI_CHECK);
307
308             default:
309               /*
310                * Makes no sense yet, may result in an endless loop
311                *
312                RequestSense(DeviceFD, &ExtendedRequestSense, 0);
313                DecodeExtSense(&ExtendedRequestSense, "SCSI_ExecuteCommand:", debug_file);
314                bcopy(&ExtendedRequestSense, RequestSenseBuf, RequestSenseLength);
315               */
316               dbprintf(("ioctl on %d return %d\n", pDev[DeviceFD].fd, Result));
317               dbprintf(("ret: %d errno: %d (%s)\n", Result, errno, ""));
318               dbprintf(("data_length:     %d\n", ds.data_length));
319               dbprintf(("buffer:          0x%X\n", ds.buffer));
320               dbprintf(("timeout_value:   %d\n", ds.timeout_value));
321               dbprintf(("status_validity: %d\n", ds.status_validity));
322               dbprintf(("scsi_bus_status: 0x%X\n", ds.scsi_bus_status));
323               dbprintf(("adapter_status:  0x%X\n", ds.adapter_status));
324               dbprintf(("adap_q_status:   0x%X\n", ds.adap_q_status));
325               dbprintf(("q_tag_msg:       0x%X\n", ds.q_tag_msg));
326               dbprintf(("flags:           0X%X\n", ds.flags));
327               return(SCSI_ERROR);
328             }
329         }
330       return(SCSI_OK);
331     }
332 }
333
334 int SCSI_Scan(void)
335 {
336   int fd;
337   struct sc_inquiry si;
338   u_char buf[255];
339   int target;
340   int lun;
341   int isbusy;
342   char type;
343   char bus[] = "/dev/scsi0";
344   
345   if ((fd = open(bus, O_RDWR)) == -1)
346     return(1);
347
348   for (target = 0; target < 7; target++) 
349     {
350       for (lun = 0; lun < 7; lun++)
351         {
352           printf("Target:Lun %d:%d\n", target,lun);
353           if (ioctl(fd, SCIOSTART, IDLUN(target, lun)) == -1) {
354             if (errno == EINVAL) {
355               printf("is in use\n");
356               isbusy = 1;
357             } else {
358               return(1);
359             }
360           } else {
361             isbusy = 0;
362           }
363           
364           bzero(&si, SIZEOF(si));
365           si.scsi_id = target;
366           si.lun_id = lun;
367           si.inquiry_len = 255;
368           si.inquiry_ptr = (char *)&buf;
369           if (ioctl(fd, SCIOINQU, &si) == -1)
370             {
371               printf("SCIOINQU: %s\n", strerror(errno));
372             } else {
373               dump_hex(&buf, 255, DEBUG_INFO, SECTION_SCSI);
374               type = buf[0] & 0x1lf;
375               buf[8+28] = 0;
376               printf("%-28s|Device Type %d\n",buf[8], type);
377             }
378           if (!isbusy && ioctl(fd, SCIOSTOP, IDLUN(target, lun)) == -1)
379             return(1);
380         }
381     }
382 }
383
384 int Tape_Ioctl(int DeviceFD, int command)
385 {
386   extern OpenFiles_T *pDev;
387   int ret = -1;
388   return(ret);
389 }
390
391 int Tape_Status( int DeviceFD)
392 {
393 /*
394   Not yet
395 */
396   return(-1);
397 }
398
399 int ScanBus(int print)
400 {
401 /*
402   Not yet
403 */
404   SCSI_Scan();
405   return(-1);
406 }
407
408 #endif
409 /*
410  * Local variables:
411  * indent-tabs-mode: nil
412  * c-file-style: gnu
413  * End:
414  */