Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-osf.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-osf.c       1.26 04/01/15 Copyright 1998 J. Schilling */
14 /*
15  *      Interface for Digital UNIX (OSF/1 generic SCSI implementation (/dev/cam).
16  *
17  *      Created out of the hacks from:
18  *              Stefan Traby <stefan@sime.com> and
19  *              Bruno Achauer <bruno@tk.uni-linz.ac.at>
20  *
21  *      Warning: you may change this source, but if you do that
22  *      you need to change the _usal_version and _usal_auth* string below.
23  *      You may not return "schily" for an SCG_AUTHOR request anymore.
24  *      Choose your name instead of "schily" and make clear that the version
25  *      string is related to a modified source.
26  *
27  *      Copyright (c) 1998 J. Schilling
28  */
29 /*
30  * This program is free software; you can redistribute it and/or modify
31  * it under the terms of the GNU General Public License version 2
32  * as published by the Free Software Foundation.
33  *
34  * This program is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37  * GNU General Public License for more details.
38  *
39  * You should have received a copy of the GNU General Public License along with
40  * this program; see the file COPYING.  If not, write to the Free Software
41  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
42  */
43
44 #include <sys/types.h>
45 #include <io/common/iotypes.h>
46 #include <io/cam/cam.h>
47 #include <io/cam/uagt.h>
48
49 /*
50  *      Warning: you may change this source, but if you do that
51  *      you need to change the _usal_version and _usal_auth* string below.
52  *      You may not return "schily" for an SCG_AUTHOR request anymore.
53  *      Choose your name instead of "schily" and make clear that the version
54  *      string is related to a modified source.
55  */
56 static  char    _usal_trans_version[] = "scsi-osf.c-1.26";      /* The version for this transport*/
57
58 #define MAX_SCG         16      /* Max # of SCSI controllers */
59 #define MAX_TGT         16
60 #define MAX_LUN         8
61
62 struct usal_local {
63         int     usalfile;       /* Used for ioctl()     */
64         short   usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
65 };
66 #define usallocal(p)    ((struct usal_local *)((p)->local))
67
68 static  BOOL    scsi_checktgt(SCSI *usalp, int f, int busno, int tgt, int tlun);
69
70 /*
71  * I don't have any documentation about CAM
72  */
73 #define MAX_DMA_OSF_CAM (64*1024)
74
75 #ifndef AUTO_SENSE_LEN
76 #       define  AUTO_SENSE_LEN  32      /* SCG_MAX_SENSE */
77 #endif
78
79 /*
80  * Return version information for the low level SCSI transport code.
81  * This has been introduced to make it easier to trace down problems
82  * in applications.
83  */
84 static char *
85 usalo_version(SCSI *usalp, int what)
86 {
87         if (usalp != (SCSI *)0) {
88                 switch (what) {
89
90                 case SCG_VERSION:
91                         return (_usal_trans_version);
92                 /*
93                  * If you changed this source, you are not allowed to
94                  * return "schily" for the SCG_AUTHOR request.
95                  */
96                 case SCG_AUTHOR:
97                         return (_usal_auth_cdrkit);
98                 case SCG_SCCS_ID:
99                         return (__sccsid);
100                 }
101         }
102         return ((char *)0);
103 }
104
105 static int
106 usalo_help(SCSI *usalp, FILE *f)
107 {
108         __usal_help(f, "CAM", "Generic transport independent SCSI (Common Access Method)",
109                 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
110         return (0);
111 }
112
113 static int
114 usalo_open(SCSI *usalp, char *device)
115 {
116                 int     busno   = usal_scsibus(usalp);
117                 int     tgt     = usal_target(usalp);
118                 int     tlun    = usal_lun(usalp);
119         register int    b;
120         register int    t;
121         register int    l;
122
123         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
124                 errno = EINVAL;
125                 if (usalp->errstr)
126                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
127                                 "Illegal value for busno, target or lun '%d,%d,%d'",
128                                 busno, tgt, tlun);
129                 return (-1);
130         }
131
132         if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
133                 errno = EINVAL;
134                 if (usalp->errstr)
135                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
136                                 "Open by 'devname' not supported on this OS");
137                 return (-1);
138         }
139
140         if (usalp->local == NULL) {
141                 usalp->local = malloc(sizeof (struct usal_local));
142                 if (usalp->local == NULL)
143                         return (0);
144                 usallocal(usalp)->usalfile = -1;
145
146                 for (b = 0; b < MAX_SCG; b++) {
147                         for (t = 0; t < MAX_TGT; t++) {
148                                 for (l = 0; l < MAX_LUN; l++)
149                                         usallocal(usalp)->usalfiles[b][t][l] = 0;
150                         }
151                 }
152         }
153
154         if (usallocal(usalp)->usalfile != -1)   /* multiple opens ??? */
155                 return (1);                     /* not yet ready .... */
156
157         if ((usallocal(usalp)->usalfile = open("/dev/cam", O_RDWR, 0)) < 0) {
158                 if (usalp->errstr)
159                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
160                                 "Cannot open '/dev/cam'");
161                 return (-1);
162         }
163
164         if (busno >= 0 && tgt >= 0 && tlun >= 0) {
165                 /* scsi_checktgt() ??? */
166                 for (l = 0; l < MAX_LUN; l++)
167                         usallocal(usalp)->usalfiles[b][t][l] = 1;
168                 return (1);
169         }
170         /*
171          * There seems to be no clean way to check whether
172          * a SCSI bus is present in the current system.
173          * scsi_checktgt() is used as a workaround for this problem.
174          */
175         for (b = 0; b < MAX_SCG; b++) {
176                 for (t = 0; t < MAX_TGT; t++) {
177                         if (scsi_checktgt(usalp, usallocal(usalp)->usalfile, b, t, 0)) {
178                                 for (l = 0; l < MAX_LUN; l++)
179                                         usallocal(usalp)->usalfiles[b][t][l] = 1;
180                                 /*
181                                  * Found a target on this bus.
182                                  * Comment the 'break' for a complete scan.
183                                  */
184                                 break;
185                         }
186                 }
187         }
188         return (1);
189 }
190
191 static int
192 usalo_close(SCSI *usalp)
193 {
194         if (usalp->local == NULL)
195                 return (-1);
196
197         if (usallocal(usalp)->usalfile >= 0)
198                 close(usallocal(usalp)->usalfile);
199         usallocal(usalp)->usalfile = -1;
200         return (0);
201 }
202
203 /*
204  * We send a test unit ready command to the target to check whether the
205  * OS is considering this target to be valid.
206  * XXX Is this really needed? We should rather let the cmd fail later.
207  */
208 static BOOL
209 scsi_checktgt(SCSI *usalp, int f, int busno, int tgt, int tlun)
210 {
211         struct usal_cmd *sp = usalp->scmd;
212         struct usal_cmd sc;
213         int     ret;
214         int     ofd  = usalp->fd;
215         int     obus = usal_scsibus(usalp);
216         int     otgt = usal_target(usalp);
217         int     olun = usal_lun(usalp);
218
219         usal_settarget(usalp, busno, tgt, tlun);
220         usalp->fd = f;
221
222         sc = *sp;
223         fillbytes((caddr_t)sp, sizeof (*sp), '\0');
224         sp->addr = (caddr_t)0;
225         sp->size = 0;
226         sp->flags = SCG_DISRE_ENA | SCG_SILENT;
227         sp->cdb_len = SC_G0_CDBLEN;
228         sp->sense_len = CCS_SENSE_LEN;
229         sp->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY;
230         sp->cdb.g0_cdb.lun = usal_lun(usalp);
231
232         usalo_send(usalp);
233         usal_settarget(usalp, obus, otgt, olun);
234         usalp->fd = ofd;
235
236         if (sp->error != SCG_FATAL)
237                 return (TRUE);
238         ret = sp->ux_errno != EINVAL;
239         *sp = sc;
240         return (ret);
241 }
242
243
244 static long
245 usalo_maxdma(SCSI *usalp, long amt)
246 {
247         long maxdma = MAX_DMA_OSF_CAM;
248
249         return (maxdma);
250 }
251
252 static void *
253 usalo_getbuf(SCSI *usalp, long amt)
254 {
255         if (usalp->debug > 0) {
256                 fprintf((FILE *)usalp->errfile,
257                         "usalo_getbuf: %ld bytes\n", amt);
258         }
259         usalp->bufbase = valloc((size_t)(amt));
260         return (usalp->bufbase);
261 }
262
263 static void
264 usalo_freebuf(SCSI *usalp)
265 {
266         if (usalp->bufbase)
267                 free(usalp->bufbase);
268         usalp->bufbase = NULL;
269 }
270
271 static BOOL
272 usalo_havebus(SCSI *usalp, int busno)
273 {
274         register int    t;
275
276         if (busno < 0 || busno >= MAX_SCG)
277                 return (FALSE);
278
279         if (usalp->local == NULL)
280                 return (FALSE);
281
282         for (t = 0; t < MAX_TGT; t++) {
283                 if (usallocal(usalp)->usalfiles[busno][t][0] != 0)
284                         return (TRUE);
285         }
286         return (FALSE);
287 }
288
289
290 static int
291 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
292 {
293         if (usalp->local == NULL)
294                 return (-1);
295
296         return ((busno < 0 || busno >= MAX_SCG) ? -1 : usallocal(usalp)->usalfile);
297 }
298
299 static int
300 usalo_initiator_id(SCSI *usalp)
301 {
302         return (-1);
303 }
304
305 static int
306 usalo_isatapi(SCSI *usalp)
307 {
308         return (FALSE);
309 }
310
311 static int
312 usalo_reset(SCSI *usalp, int what)
313 {
314         errno = EINVAL;
315         return (-1);
316 }
317
318 static int
319 usalo_send(SCSI *usalp)
320 {
321         struct usal_cmd *sp = usalp->scmd;
322         CCB_SCSIIO      ccb;
323         UAGT_CAM_CCB    ua;
324         unsigned char   *cdb;
325         CCB_RELSIM      relsim;
326         UAGT_CAM_CCB    relua;
327         int             i;
328
329         if (usalp->fd < 0) {
330                 sp->error = SCG_FATAL;
331                 return (0);
332         }
333
334         fillbytes(&ua, sizeof (UAGT_CAM_CCB), 0);
335         fillbytes(&ccb, sizeof (CCB_SCSIIO), 0);
336
337         ua.uagt_ccb = (CCB_HEADER *) &ccb;
338         ua.uagt_ccblen = sizeof (CCB_SCSIIO);
339         ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb;
340         ccb.cam_ch.cam_ccb_len = sizeof (CCB_SCSIIO);
341
342         ua.uagt_snsbuf = ccb.cam_sense_ptr = sp->u_sense.cmd_sense;
343         ua.uagt_snslen = ccb.cam_sense_len = AUTO_SENSE_LEN;
344
345         cdb = (unsigned char *) ccb.cam_cdb_io.cam_cdb_bytes;
346
347         ccb.cam_timeout = sp->timeout;
348
349         ccb.cam_data_ptr = ua.uagt_buffer = (Uchar *) sp->addr;
350         ccb.cam_dxfer_len = ua.uagt_buflen = sp->size;
351         ccb.cam_ch.cam_func_code = XPT_SCSI_IO;
352         ccb.cam_ch.cam_flags = 0;       /* CAM_DIS_CALLBACK; */
353
354         if (sp->size == 0) {
355                 ccb.cam_data_ptr = ua.uagt_buffer = (Uchar *) NULL;
356                 ccb.cam_ch.cam_flags |= CAM_DIR_NONE;
357         } else {
358                 if (sp->flags & SCG_RECV_DATA) {
359                         ccb.cam_ch.cam_flags |= CAM_DIR_IN;
360                 } else {
361                         ccb.cam_ch.cam_flags |= CAM_DIR_OUT;
362                 }
363         }
364
365         ccb.cam_cdb_len = sp->cdb_len;
366         for (i = 0; i < sp->cdb_len; i++)
367                 cdb[i] = sp->cdb.cmd_cdb[i];
368
369         ccb.cam_ch.cam_path_id    = usal_scsibus(usalp);
370         ccb.cam_ch.cam_target_id  = usal_target(usalp);
371         ccb.cam_ch.cam_target_lun = usal_lun(usalp);
372
373         sp->sense_count = 0;
374         sp->ux_errno = 0;
375         sp->error = SCG_NO_ERROR;
376
377
378         if (ioctl(usalp->fd, UAGT_CAM_IO, (caddr_t) &ua) < 0) {
379                 sp->ux_errno = geterrno();
380                 sp->error = SCG_FATAL;
381                 if (usalp->debug > 0) {
382                         errmsg("ioctl(fd, UAGT_CAM_IO, dev=%d,%d,%d) failed.\n",
383                                         usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
384                 }
385                 return (0);
386         }
387         if (usalp->debug > 0) {
388                 errmsgno(EX_BAD, "cam_status = 0x%.2X scsi_status = 0x%.2X dev=%d,%d,%d\n",
389                                         ccb.cam_ch.cam_status,
390                                         ccb.cam_scsi_status,
391                                         usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
392                 fflush(stderr);
393         }
394         switch (ccb.cam_ch.cam_status & CAM_STATUS_MASK) {
395
396         case CAM_REQ_CMP:       break;
397
398         case CAM_SEL_TIMEOUT:   sp->error = SCG_FATAL;
399                                 sp->ux_errno = EIO;
400                                 break;
401
402         case CAM_CMD_TIMEOUT:   sp->error = SCG_TIMEOUT;
403                                 sp->ux_errno = EIO;
404                                 break;
405
406         default:                sp->error = SCG_RETRYABLE;
407                                 sp->ux_errno = EIO;
408                                 break;
409         }
410
411         sp->u_scb.cmd_scb[0] = ccb.cam_scsi_status;
412
413         if (ccb.cam_ch.cam_status & CAM_AUTOSNS_VALID) {
414                 sp->sense_count = MIN(ccb.cam_sense_len - ccb.cam_sense_resid,
415                         SCG_MAX_SENSE);
416                 sp->sense_count = MIN(sp->sense_count, sp->sense_len);
417                 if (sp->sense_len < 0)
418                         sp->sense_count = 0;
419         }
420         sp->resid = ccb.cam_resid;
421
422
423         /*
424          * this is perfectly wrong.
425          * But without this, we hang...
426          */
427         if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN) {
428                 fillbytes(&relsim, sizeof (CCB_RELSIM), 0);
429                 relsim.cam_ch.cam_ccb_len = sizeof (CCB_SCSIIO);
430                 relsim.cam_ch.cam_func_code = XPT_REL_SIMQ;
431                 relsim.cam_ch.cam_flags = CAM_DIR_IN | CAM_DIS_CALLBACK;
432                 relsim.cam_ch.cam_path_id       = usal_scsibus(usalp);
433                 relsim.cam_ch.cam_target_id     = usal_target(usalp);
434                 relsim.cam_ch.cam_target_lun    = usal_lun(usalp);
435
436                 relua.uagt_ccb = (struct ccb_header *) & relsim;        /* wrong cast */
437                 relua.uagt_ccblen = sizeof (relsim);
438                 relua.uagt_buffer = NULL;
439                 relua.uagt_buflen = 0;
440
441                 if (ioctl(usalp->fd, UAGT_CAM_IO, (caddr_t) & relua) < 0)
442                         errmsg("DEC CAM -> LMA\n");
443         }
444         return (0);
445 }