Imported Upstream version 3.1.0
[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 #include <scsi-defs.h>
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(void)
65 {
66 #ifndef lint
67    static char rcsid[] = "$Id: scsi-aix.c,v 1.23 2006/05/25 01:47:07 johnfranks 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            }
130            free(pDev[ip].inquiry);
131            pDev[ip].inquiry = NULL;
132            return(1);
133        } else {
134          dbprintf(_("SCSI_OpenDevice %s failed\n"), pDev[ip].dev);
135          return(0);
136        }
137     } else {
138       if ((DeviceFD = openx(pDev[ip].dev, O_RDWR, 0, SC_DIAGNOSTIC)) >= 0)
139         {
140           pDev[ip].fd = DeviceFD;
141           pDev[ip].devopen = 1;
142           return(1);
143         }
144     }
145   return(0);
146 }
147
148 int SCSI_CloseDevice(int DeviceFD)
149 {
150   int ret;
151   extern OpenFiles_T *pDev;
152
153   ret = close(pDev[DeviceFD].fd);
154   pDev[DeviceFD].devopen = 0;
155   return(ret);
156
157 }
158
159 int SCSI_ExecuteCommand(int DeviceFD,
160                         Direction_T Direction,
161                         CDB_T CDB,
162                         size_t CDB_Length,
163                         void *DataBuffer,
164                         size_t DataBufferLength,
165                         RequestSense_T *RequestSenseBuf,
166                         size_t RequestSenseLength)
167 {
168   extern OpenFiles_T *pDev;
169   extern FILE * debug_file;
170   CDB_T CDBSENSE;
171   CDB_T SINQ;
172   ExtendedRequestSense_T ExtendedRequestSense;
173   struct sc_iocmd ds;
174   scmd_t scmd;
175   char sbyte;
176   int Result;
177   int isbusy = 0;
178   int target = 3;
179
180   /* Basic sanity checks */
181   assert(CDB_Length <= UCHAR_MAX);
182   assert(RequestSenseLength <= UCHAR_MAX);
183
184   /* Clear buffer for cases where sense is not returned */
185   memset(RequestSenseBuf, 0, RequestSenseLength);
186
187   if (pDev[DeviceFD].avail == 0)
188     {
189       return(SCSI_ERROR);
190     }
191
192
193   if (pDev[DeviceFD].flags == AIX_USE_GSC)
194     {
195       scmd.cdb = CDB;
196       scmd.cdblen = CDB_Length;
197       scmd.data_buf = DataBuffer;
198       scmd.datalen = DataBufferLength;
199       scmd.sense_buf = (unsigned char *)RequestSenseBuf;
200       scmd.senselen = RequestSenseLength;
201       scmd.statusp = &sbyte;
202       scmd.timeval = 60;
203       switch (Direction) 
204         {
205         case Input:
206           scmd.rw = 0;
207           break;
208         case Output:
209           scmd.rw = 1;
210           break;
211         }
212
213       if (ioctl(pDev[DeviceFD].fd, GSC_CMD, (caddr_t) &scmd) < 0) {
214         return(SCSI_ERROR);
215       }
216       return(SCSI_OK);
217
218     } else {
219       bzero(&ds, SIZEOF(struct sc_iocmd));
220       bzero(RequestSenseBuf, RequestSenseLength);
221       bzero(&ExtendedRequestSense, SIZEOF(ExtendedRequestSense_T));
222       
223       ds.flags = SC_ASYNC; 
224       /* Timeout */
225       ds.timeout_value = 60;
226       bcopy(CDB, ds.scsi_cdb, CDB_Length);
227       ds.command_length = CDB_Length;
228       /* 
229        *  Data buffer for results 
230        * If the size of the buffer is 0
231        * then keep this fields untouched           
232        */
233       if (DataBufferLength > 0)
234         {
235           ds.buffer = DataBuffer;
236           ds.data_length = DataBufferLength;
237         }
238       
239       /* Sense Buffer is not available on AIX ?*/
240       /*
241         ds.req_sense_length = 255;
242         ds.request_sense_ptr = (unsigned char *)RequestSense;
243       */
244       switch (Direction) 
245         {
246         case Input:
247           ds.flags = ds.flags | B_READ;
248           break;
249         case Output:
250           ds.flags = ds.flags | B_WRITE;
251           break;
252         }
253       DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
254       
255       if (pDev[DeviceFD].devopen == 0)
256         if (SCSI_OpenDevice(DeviceFD) == 0)
257           return(SCSI_ERROR);
258       Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
259       SCSI_CloseDevice(DeviceFD);
260       
261       if ( Result < 0)
262         {
263           switch (ds.scsi_bus_status)
264             {
265             case SC_GOOD_STATUS:
266               SINQ[0] = SC_COM_REQUEST_SENSE;
267               SINQ[1] = 0; 
268               SINQ[2] = 0;
269               SINQ[3] = 0;
270               SINQ[4] = 0x1D;
271               SINQ[5] = 0x80;
272               bcopy(SINQ, ds.scsi_cdb, 6);
273               ds.command_length = 6;
274               ds.buffer = (unsigned char *)RequestSenseBuf;
275               ds.data_length = RequestSenseLength;
276               
277               if (pDev[DeviceFD].devopen == 0)
278                 if (SCSI_OpenDevice(DeviceFD) == 0)
279                   return(SCSI_ERROR);
280               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
281               SCSI_CloseDevice(DeviceFD);
282               return(SCSI_OK);
283
284             case SC_BUSY_STATUS:
285               return(SCSI_BUSY);
286
287             case SC_CHECK_CONDITION:
288               SINQ[0] = SC_COM_REQUEST_SENSE;
289               SINQ[1] = 0; 
290               SINQ[2] = 0;
291               SINQ[3] = 0;
292               SINQ[4] = 0x1D;
293               SINQ[5] = 0x80;
294               bcopy(SINQ, ds.scsi_cdb, 6);
295               ds.command_length = 6;
296               ds.buffer = (unsigned char *)RequestSenseBuf;
297               ds.data_length = (unsigned char)RequestSenseLength;
298
299               if (pDev[DeviceFD].devopen == 0)
300                 if (SCSI_OpenDevice(DeviceFD) == 0)
301                   return(SCSI_ERROR);
302               Result = ioctl(pDev[DeviceFD].fd, STIOCMD, &ds);
303               SCSI_CloseDevice(DeviceFD);
304               return(SCSI_CHECK);
305
306             default:
307               /*
308                * Makes no sense yet, may result in an endless loop
309                *
310                RequestSense(DeviceFD, &ExtendedRequestSense, 0);
311                DecodeExtSense(&ExtendedRequestSense, "SCSI_ExecuteCommand:", debug_file);
312                bcopy(&ExtendedRequestSense, RequestSenseBuf, RequestSenseLength);
313               */
314               dbprintf(_("ioctl on %d return %d\n"), pDev[DeviceFD].fd, Result);
315               dbprintf(_("ret: %d errno: %d (%s)\n"), Result, errno, "");
316               dbprintf(_("data_length:     %d\n"), ds.data_length);
317               dbprintf(_("buffer:          0x%X\n"), ds.buffer);
318               dbprintf(_("timeout_value:   %d\n"), ds.timeout_value);
319               dbprintf(_("status_validity: %d\n"), ds.status_validity);
320               dbprintf(_("scsi_bus_status: 0x%X\n"), ds.scsi_bus_status);
321               dbprintf(_("adapter_status:  0x%X\n"), ds.adapter_status);
322               dbprintf(_("adap_q_status:   0x%X\n"), ds.adap_q_status);
323               dbprintf(_("q_tag_msg:       0x%X\n"), ds.q_tag_msg);
324               dbprintf(_("flags:           0X%X\n"), ds.flags);
325               return(SCSI_ERROR);
326             }
327         }
328       return(SCSI_OK);
329     }
330 }
331
332 int SCSI_Scan(void)
333 {
334   int fd;
335   struct sc_inquiry si;
336   u_char buf[255];
337   int target;
338   int lun;
339   int isbusy;
340   char type;
341   char bus[] = "/dev/scsi0";
342   
343   if ((fd = open(bus, O_RDWR)) == -1)
344     return(1);
345
346   for (target = 0; target < 7; target++) 
347     {
348       for (lun = 0; lun < 7; lun++)
349         {
350           g_printf(_("Target:Lun %d:%d\n"), target,lun);
351           if (ioctl(fd, SCIOSTART, IDLUN(target, lun)) == -1) {
352             if (errno == EINVAL) {
353               g_printf(_("is in use\n"));
354               isbusy = 1;
355             } else {
356               return(1);
357             }
358           } else {
359             isbusy = 0;
360           }
361           
362           bzero(&si, SIZEOF(si));
363           si.scsi_id = target;
364           si.lun_id = lun;
365           si.inquiry_len = 255;
366           si.inquiry_ptr = (char *)&buf;
367           if (ioctl(fd, SCIOINQU, &si) == -1)
368             {
369               g_printf("SCIOINQU: %s\n", strerror(errno));
370             } else {
371               dump_hex(&buf, 255, DEBUG_INFO, SECTION_SCSI);
372               type = buf[0] & 0x1lf;
373               buf[8+28] = 0;
374               g_printf(_("%-28s|Device Type %d\n"),buf[8], type);
375             }
376           if (!isbusy && ioctl(fd, SCIOSTOP, IDLUN(target, lun)) == -1)
377             return(1);
378         }
379     }
380 }
381
382 int Tape_Ioctl(int DeviceFD, int command)
383 {
384   extern OpenFiles_T *pDev;
385   int ret = -1;
386   return(ret);
387 }
388
389 int Tape_Status( int DeviceFD)
390 {
391 /*
392   Not yet
393 */
394   return(-1);
395 }
396
397 int ScanBus(int print)
398 {
399 /*
400   Not yet
401 */
402   SCSI_Scan();
403   return(-1);
404 }
405
406 /*
407  * Local variables:
408  * indent-tabs-mode: nil
409  * c-file-style: gnu
410  * End:
411  */