Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-aix.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)scsi-aix.c       1.36 04/01/14 Copyright 1997 J. Schilling */
14 /*
15  *      Interface for the AIX generic SCSI implementation.
16  *
17  *      This is a hack, that tries to emulate the functionality
18  *      of the usal driver.
19  *
20  *      Warning: you may change this source, but if you do that
21  *      you need to change the _usal_version and _usal_auth* string below.
22  *      You may not return "schily" for an SCG_AUTHOR request anymore.
23  *      Choose your name instead of "schily" and make clear that the version
24  *      string is related to a modified source.
25  *
26  *      Copyright (c) 1997 J. Schilling
27  */
28 /*
29  * This program is free software; you can redistribute it and/or modify
30  * it under the terms of the GNU General Public License version 2
31  * as published by the Free Software Foundation.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License along with
39  * this program; see the file COPYING.  If not, write to the Free Software
40  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41  */
42
43 #include <sys/scdisk.h>
44
45 /*
46  *      Warning: you may change this source, but if you do that
47  *      you need to change the _usal_version and _usal_auth* string below.
48  *      You may not return "schily" for an SCG_AUTHOR request anymore.
49  *      Choose your name instead of "schily" and make clear that the version
50  *      string is related to a modified source.
51  */
52 static  char    _usal_trans_version[] = "scsi-aix.c-1.36";      /* The version for this transport*/
53
54
55 #define MAX_SCG         16      /* Max # of SCSI controllers */
56 #define MAX_TGT         16
57 #define MAX_LUN         8
58
59 struct usal_local{
60         short   usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
61 };
62 #define usallocal(p)    ((struct usal_local*)((p)->local))
63
64 #define MAX_DMA_AIX (64*1024)
65
66 static  int     do_usal_cmd(SCSI *usalp, struct usal_cmd *sp);
67 static  int     do_usal_sense(SCSI *usalp, struct usal_cmd *sp);
68
69 /*
70  * Return version information for the low level SCSI transport code.
71  * This has been introduced to make it easier to trace down problems
72  * in applications.
73  */
74 static char *
75 usalo_version(SCSI *usalp, int what)
76 {
77         if (usalp != (SCSI *)0) {
78                 switch (what) {
79
80                 case SCG_VERSION:
81                         return (_usal_trans_version);
82                 /*
83                  * If you changed this source, you are not allowed to
84                  * return "schily" for the SCG_AUTHOR request.
85                  */
86                 case SCG_AUTHOR:
87                         return (_usal_auth_cdrkit);
88                 case SCG_SCCS_ID:
89                         return (__sccsid);
90                 }
91         }
92         return ((char *)0);
93 }
94
95 static int
96 usalo_help(SCSI *usalp, FILE *f)
97 {
98         __usal_help(f, "DKIOCMD", "SCSI transport for targets known by AIX drivers",
99                 "", "bus,target,lun or UNIX device", "1,2,0 or /dev/rcd0@", FALSE, TRUE);
100         return (0);
101 }
102
103 static int
104 usalo_open(SCSI *usalp, char *device)
105 {
106                 int     busno   = usal_scsibus(usalp);
107                 int     tgt     = usal_target(usalp);
108                 int     tlun    = usal_lun(usalp);
109         register int    f;
110         register int    b;
111         register int    t;
112         register int    l;
113         register int    nopen = 0;
114         char            devname[32];
115
116         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
117                 errno = EINVAL;
118                 if (usalp->errstr)
119                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
120                                 "Illegal value for busno, target or lun '%d,%d,%d'",
121                                 busno, tgt, tlun);
122                 return (-1);
123         }
124
125         if (usalp->local == NULL) {
126                 usalp->local = malloc(sizeof (struct usal_local));
127                 if (usalp->local == NULL)
128                         return (0);
129
130                 for (b = 0; b < MAX_SCG; b++) {
131                         for (t = 0; t < MAX_TGT; t++) {
132                                 for (l = 0; l < MAX_LUN; l++)
133                                         usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
134                         }
135                 }
136         }
137
138         if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2))
139                 goto openbydev;
140
141         if (busno >= 0 && tgt >= 0 && tlun >= 0) {
142
143                 snprintf(devname, sizeof (devname), "/dev/rcd%d", tgt);
144                 f = openx(devname, 0, 0, SC_DIAGNOSTIC);
145                 if (f < 0) {
146                         if (usalp->errstr)
147                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
148                                         "Cannot open '%s'. Specify device number (1 for cd1) as target (1,0)",
149                                         devname);
150                         return (0);
151                 }
152                 usallocal(usalp)->usalfiles[busno][tgt][tlun] = f;
153                 return (1);
154         } else {
155                 if (usalp->errstr)
156                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
157                                 "Unable to scan on AIX");
158                 return (0);
159         }
160 openbydev:
161         if (device != NULL && *device != '\0' && busno >= 0 && tgt >= 0 && tlun >= 0) {
162                 f = openx(device, 0, 0, SC_DIAGNOSTIC);
163                 if (f < 0) {
164                         if (usalp->errstr)
165                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
166                                         "Cannot open '%s'",
167                                         devname);
168                         return (0);
169                 }
170
171                 usallocal(usalp)->usalfiles[busno][tgt][tlun] = f;
172                 usal_settarget(usalp, busno, tgt, tlun);
173
174                 return (++nopen);
175         }
176         return (nopen);
177 }
178
179 static int
180 usalo_close(SCSI *usalp)
181 {
182         register int    f;
183         register int    b;
184         register int    t;
185         register int    l;
186
187         if (usalp->local== NULL)
188                 return (-1);
189
190         for (b = 0; b < MAX_SCG; b++) {
191                 for (t = 0; t < MAX_TGT; t++) {
192                         for (l = 0; l < MAX_LUN; l++) {
193                                 f = usallocal(usalp)->usalfiles[b][t][l];
194                                 if (f >= 0)
195                                         close(f);
196                                 usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
197                         }
198                 }
199         }
200         return (0);
201 }
202
203 static long
204 usalo_maxdma(SCSI *usalp, long amt)
205 {
206         return (MAX_DMA_AIX);
207 }
208
209 #define palign(x, a)    (((char *)(x)) + ((a) - 1 - (((UIntptr_t)((x)-1))%(a))))
210
211 static void *
212 usalo_getbuf(SCSI *usalp, long amt)
213 {
214 /* assume having a modern AIX here */
215 #ifdef HAVE_ALLOCA_H
216     usalp->bufbase = (void *)valloc((size_t)amt);
217     return (usalp->bufbase);
218 #else
219         void    *ret;
220         int     pagesize = getpagesize();
221
222         if (usalp->debug > 0) {
223                 fprintf((FILE *)usalp->errfile,
224                                 "usalo_getbuf: %ld bytes\n", amt);
225         }
226         /*
227          * Damn AIX is a paged system but has no valloc()
228          */
229         usalp->bufbase = ret = malloc((size_t)(amt+pagesize));
230         if (ret == NULL)
231                 return (ret);
232         ret = palign(ret, pagesize);
233         return (ret);
234 #endif
235 }
236
237 static void
238 usalo_freebuf(SCSI *usalp)
239 {
240         if (usalp->bufbase)
241                 free(usalp->bufbase);
242         usalp->bufbase = NULL;
243 }
244
245 static BOOL
246 usalo_havebus(SCSI *usalp, int busno)
247 {
248         register int    t;
249         register int    l;
250
251         if (busno < 0 || busno >= MAX_SCG)
252                 return (FALSE);
253
254         if (usalp->local == NULL)
255                 return (FALSE);
256
257         for (t = 0; t < MAX_TGT; t++) {
258                 for (l = 0; l < MAX_LUN; l++)
259                         if (usallocal(usalp)->usalfiles[busno][t][l] >= 0)
260                                 return (TRUE);
261         }
262         return (FALSE);
263 }
264
265 static int
266 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
267 {
268         if (busno < 0 || busno >= MAX_SCG ||
269             tgt < 0 || tgt >= MAX_TGT ||
270             tlun < 0 || tlun >= MAX_LUN)
271                 return (-1);
272
273         if (usalp->local == NULL)
274                 return (-1);
275
276         return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]);
277 }
278
279 static int
280 usalo_initiator_id(SCSI *usalp)
281 {
282         return (-1);
283 }
284
285 static int
286 usalo_isatapi(SCSI *usalp)
287 {
288         return (FALSE);
289 }
290
291 static int
292 usalo_reset(SCSI *usalp, int what)
293 {
294         if (what == SCG_RESET_NOP)
295                 return (0);
296         if (what != SCG_RESET_BUS) {
297                 errno = EINVAL;
298                 return (-1);
299         }
300         /*
301          * XXX Does this reset TGT or BUS ???
302          */
303         return (ioctl(usalp->fd, SCIORESET, IDLUN(usal_target(usalp), usal_lun(usalp))));
304 }
305
306 static int
307 do_usal_cmd(SCSI *usalp, struct usal_cmd *sp)
308 {
309         struct sc_iocmd req;
310         int     ret;
311
312         if (sp->cdb_len > 12)
313                 comerrno(EX_BAD, "Can't do %d byte command.\n", sp->cdb_len);
314
315         fillbytes(&req, sizeof (req), '\0');
316
317         req.flags = SC_ASYNC;
318         if (sp->flags & SCG_RECV_DATA) {
319                 req.flags |= B_READ;
320         } else if (sp->size > 0) {
321                 req.flags |= B_WRITE;
322         }
323         req.data_length = sp->size;
324         req.buffer = sp->addr;
325         req.timeout_value = sp->timeout;
326         req.command_length = sp->cdb_len;
327
328         movebytes(&sp->cdb, req.scsi_cdb, 12);
329         errno = 0;
330         ret = ioctl(usalp->fd, DKIOCMD, &req);
331
332         if (usalp->debug > 0) {
333                 fprintf((FILE *)usalp->errfile, "ret: %d errno: %d (%s)\n", ret, errno, errmsgstr(errno));
334                 fprintf((FILE *)usalp->errfile, "data_length:     %d\n", req.data_length);
335                 fprintf((FILE *)usalp->errfile, "buffer:          0x%X\n", req.buffer);
336                 fprintf((FILE *)usalp->errfile, "timeout_value:   %d\n", req.timeout_value);
337                 fprintf((FILE *)usalp->errfile, "status_validity: %d\n", req.status_validity);
338                 fprintf((FILE *)usalp->errfile, "scsi_bus_status: 0x%X\n", req.scsi_bus_status);
339                 fprintf((FILE *)usalp->errfile, "adapter_status:  0x%X\n", req.adapter_status);
340                 fprintf((FILE *)usalp->errfile, "adap_q_status:   0x%X\n", req.adap_q_status);
341                 fprintf((FILE *)usalp->errfile, "q_tag_msg:       0x%X\n", req.q_tag_msg);
342                 fprintf((FILE *)usalp->errfile, "flags:           0X%X\n", req.flags);
343         }
344         if (ret < 0) {
345                 sp->ux_errno = geterrno();
346                 /*
347                  * Check if SCSI command cound not be send at all.
348                  */
349                 if (sp->ux_errno == ENOTTY || sp->ux_errno == ENXIO ||
350                     sp->ux_errno == EINVAL || sp->ux_errno == EACCES) {
351                         return (-1);
352                 }
353         } else {
354                 sp->ux_errno = 0;
355         }
356         ret = 0;
357         sp->sense_count = 0;
358         sp->resid = 0;          /* AIX is the same rubbish as Linux here */
359
360         fillbytes(&sp->scb, sizeof (sp->scb), '\0');
361         fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0');
362
363         if (req.status_validity == 0) {
364                 sp->error = SCG_NO_ERROR;
365                 return (0);
366         }
367         if (req.status_validity & 1) {
368                 sp->u_scb.cmd_scb[0] = req.scsi_bus_status;
369                 sp->error = SCG_RETRYABLE;
370         }
371         if (req.status_validity & 2) {
372                 if (req.adapter_status & SC_NO_DEVICE_RESPONSE) {
373                         sp->error = SCG_FATAL;
374
375                 } else if (req.adapter_status & SC_CMD_TIMEOUT) {
376                         sp->error = SCG_TIMEOUT;
377
378                 } else if (req.adapter_status != 0) {
379                         sp->error = SCG_RETRYABLE;
380                 }
381         }
382
383         return (ret);
384 }
385
386 static int
387 do_usal_sense(SCSI *usalp, struct usal_cmd *sp)
388 {
389         int             ret;
390         struct usal_cmd s_cmd;
391
392         fillbytes((caddr_t)&s_cmd, sizeof (s_cmd), '\0');
393         s_cmd.addr = sp->u_sense.cmd_sense;
394         s_cmd.size = sp->sense_len;
395         s_cmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA;
396         s_cmd.cdb_len = SC_G0_CDBLEN;
397         s_cmd.sense_len = CCS_SENSE_LEN;
398         s_cmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
399         s_cmd.cdb.g0_cdb.lun = sp->cdb.g0_cdb.lun;
400         s_cmd.cdb.g0_cdb.count = sp->sense_len;
401         ret = do_usal_cmd(usalp, &s_cmd);
402
403         if (ret < 0)
404                 return (ret);
405         if (s_cmd.u_scb.cmd_scb[0] & 02) {
406                 /* XXX ??? Check condition on request Sense ??? */
407         }
408         sp->sense_count = sp->sense_len - s_cmd.resid;
409         return (ret);
410 }
411
412 static int
413 usalo_send(SCSI *usalp)
414 {
415         struct usal_cmd *sp = usalp->scmd;
416         int     ret;
417
418         if (usalp->fd < 0) {
419                 sp->error = SCG_FATAL;
420                 return (0);
421         }
422         ret = do_usal_cmd(usalp, sp);
423         if (ret < 0)
424                 return (ret);
425         if (sp->u_scb.cmd_scb[0] & 02)
426                 ret = do_usal_sense(usalp, sp);
427         return (ret);
428 }