Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-openserver.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-openserver.c        1.31 04/01/15 Copyright 1998 J. Schilling, Santa Cruz Operation */
14 /*
15  *      Interface for the SCO SCSI implementation.
16  *
17  *      Warning: you may change this source, but if you do that
18  *      you need to change the _usal_version and _usal_auth* string below.
19  *      You may not return "schily" for an SCG_AUTHOR request anymore.
20  *      Choose your name instead of "schily" and make clear that the version
21  *      string is related to a modified source.
22  *
23  *      Copyright (c) 1998 J. Schilling, Santa Cruz Operation
24  */
25 /*
26  * This program is free software; you can redistribute it and/or modify
27  * it under the terms of the GNU General Public License version 2
28  * as published by the Free Software Foundation.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License along with
36  * this program; see the file COPYING.  If not, write to the Free Software
37  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38  */
39
40 #undef  sense
41
42 #include <sys/scsicmd.h>
43
44 /*
45  *      Warning: you may change this source, but if you do that
46  *      you need to change the _usal_version and _usal_auth* string below.
47  *      You may not return "schily" for an SCG_AUTHOR request anymore.
48  *      Choose your name instead of "schily" and make clear that the version
49  *      string is related to a modified source.
50  */
51 static  char    _usal_trans_version[] = "scsi-openserver.c-1.31";       /* The version for this transport*/
52
53 #define MAX_SCG         16              /* Max # of cdrom devices */
54 #define MAX_TGT         16              /* Not really needed      */
55 #define MAX_LUN         8               /* Not really needed      */
56
57 #define MAX_DMA         (64*1024)
58
59 #define MAXPATH         256             /* max length of devicepath  */
60 #define MAXLINE         80              /* max length of input line  */
61 #define MAXSCSI         99              /* max number of mscsi lines */
62 #define MAXDRVN         10              /* max length of drivername  */
63
64 #define DEV_DIR         "/tmp"
65 #define DEV_NAME        "usal.s%1dt%1dl%1d"
66
67 /*
68  * ---------------------------------------------------------------------
69  * We will only deal with cdroms by default! Only if you set a specific
70  * environment variable, we will scan "all" devices !
71  * Set LIBSCG_SCAN_ALL to any value to enable access to all your SCSI
72  * devices.
73  *
74  * The upcoming support for USB will be for USB 1.1, so as this is not
75  * tested yet, we will currently ignore drives connect to the USB stack
76  * (usbha controller) regardless of having set LIBSCG_SCAN_ALL or not!
77  */
78
79 #define DEV_ROOT        "/dev/dsk/0s0"
80
81 #define DEV_SDSK        "/dev/rdsk/%ds0"
82 #define DEV_SROM        "/dev/rcd%d"
83 #define DEV_STP         "/dev/xStp%d"
84 #define DEV_SFLP        "/dev/rdsk/fp%dh"
85
86 #define SCAN_DEV        "%s%s%d%d%d%d"
87
88 #define SCSI_CFG        "/etc/sconf -r"         /* no. of configured devices  */
89 #define SCSI_DEV        "/etc/sconf -g %d"      /* read line 'n' of mscsi tbl */
90
91 #define DRV_ATAPI       "wd"            /* SCO OpenServer IDE driver    */
92 #define DRV_USB         "usbha"         /* SCO OpenServer USB driver    */
93 #define DRV_NOHA        "noha"          /* IDE/ATAPI device configured, */
94                                         /* but missing !                */
95
96
97 #define T_DISK          "Sdsk"          /* SCO OpenServer SCSI disk     */
98 #define T_CDROM         "Srom"          /* SCO OpenServer SCSI cdrom    */
99 #define T_TAPE          "Stp"           /* SCO OpenServer SCSI tape     */
100 #define T_FLOPPY        "Sflp"          /* SCO OpenServer SCSI floppy   */
101
102
103 /*
104  * ---------------------------------------------------------------------
105  * Environment variables to control certain functionality
106  */
107
108 #define SCAN_ALL        "LIBSCG_SCAN_ALL"       /* enable access for all devices */
109 #define SCSI_USER_CMD   "LIBSCG_SCSIUSERCMD"    /* use old SCSIUSERCMD ioctl() */
110 #define DMA_OVERRIDE    "LIBSCG_MAX_DMA"        /* override MAX_DMA value */
111 #define ENABLE_USB      "LIBSCG_ENABLE_USB"     /* enable access of USB devices */
112
113 static  int     scan_all        = 0;    /* don't scan all devices by default */
114 static  int     scsiusercmd     = 0;    /* use SCSIUSERCMD2 ioctl by default */
115 static  int     enable_usb      = 0;    /* don't scan USB devices by default */
116 static  long    max_dma         = MAX_DMA; /* use MAX_DMA DMA buffer by default */
117
118
119 /*
120  * ---------------------------------------------------------------------
121  * There are two scsi passthrough ioctl() on SCO OpenServer 5.0.[45],
122  * while there is only one available on SCO OpenServer 5.0.[02].
123  *
124  * The SCSIUSERCMD ioctl is available on all OpenServer 5
125  *
126  * The SCSIUSERCMD2 ioctl which executes the usercmd and reads the sense
127  * in one go, is only available from 5.0.4 onwards.
128  *
129  * By default we will use the SCSIUSERCMD2 ioctl(), in order to execute
130  * the SCSIUSERCMD ioctl() instead set the environment variable
131  * LIBSCG_SCSIUSERCMD to any value. Using the olderSCSIUSERCMD ioctl() will
132  * if the SCSI commands returns a CHECK CONDITION status, run a seperate
133  * REQUEST_SENSE command immediately. But we need to remember that in a
134  * multi-tasking environment, there might be other code which has accessed
135  * the device in between these two steps and therefore the sense code
136  * is no longer valid !!!
137  *
138  * NOTE: There are problems with the usage of AHA 154X controllers
139  * and SCSIUSERCMD2 such as nonsense (weird) output on cdrecord -scanbus
140  *
141  */
142
143
144 typedef struct usal2sdi {
145
146         int     valid;
147         int     open;
148         int     atapi;
149         int     fd;
150         int     lmscsi;
151
152 } usal2sdi_t;
153
154 static  usal2sdi_t      sdidevs [MAX_SCG][MAX_TGT][MAX_LUN];
155
156 typedef struct amscsi {
157         char    typ[MAXDRVN];
158         char    drv[MAXDRVN];
159         int     hba;
160         int     bus;
161         int     usal;
162         int     tgt;
163         int     lun;
164         char    dev[MAXPATH];
165
166 } amscsi_t;
167
168 struct usal_local {
169         short   usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
170 };
171 #define usallocal(p)    ((struct usal_local *)((p)->local))
172
173 static  int     sort_mscsi(const void *l1, const void *l2);
174 static  int     openserver_init(SCSI *usalp);
175 static  void    cp_usal2sco(struct scsicmd2 *sco, struct usal_cmd *usal);
176 static  void    cp_sco2usal(struct scsicmd2 *sco, struct usal_cmd *usal);
177
178 /*
179  * -------------------------------------------------------------------------
180  * SCO OpenServer does not have a generic scsi device driver, which can
181  * be used to access any configured scsi device. But we can use the "Sxxx"
182  * scsi peripherial drivers passthrough ioctl() (SCSIUSERCMD / SCSIUSERCMD2)
183  * to send scsi user comands to any target device controlled by the
184  * corresponding target driver.
185  *
186  * This passthrough implementation for libusal currently allows to
187  * handle the following devices classes:
188  *
189  *      1. DISK         handled by Sdsk
190  *      2. CD-ROM       handled by Srom
191  *      3. TAPES        handled by Stp
192  *      4. FLOPPY       handled by Sflp
193  *
194  * NOTE: The libusal OpenServer passthrough routines have changed with
195  *       cdrecord-1.8 to enable the -scanbus option. Therefore the
196  *       addressing scheme is now the same as used on many other platforms
197  *       like Solaris, Linux etc.
198  *
199  *   ===============================================================
200  *   RUN 'cdrecord -scanbus' TO SEE THE DEVICE ADDRESSES YOU CAN USE
201  *   ===============================================================
202  *
203  */
204
205 /*
206  * Return version information for the low level SCSI transport code.
207  * This has been introduced to make it easier to trace down problems
208  * in applications.
209  */
210 static char *
211 usalo_version(SCSI *usalp, int what)
212 {
213         if (usalp != (SCSI *)0) {
214                 switch (what) {
215
216                 case SCG_VERSION:
217                         return (_usal_trans_version);
218                 /*
219                  * If you changed this source, you are not allowed to
220                  * return "schily" for the SCG_AUTHOR request.
221                  */
222                 case SCG_AUTHOR:
223                         return (_usal_auth_cdrkit);
224                 case SCG_SCCS_ID:
225                         return (__sccsid);
226                 }
227         }
228         return ((char *)0);
229 }
230
231 static int
232 usalo_help(SCSI *usalp, FILE *f)
233 {
234         __usal_help(f, "SCSIUSERCMD/SCSIUSERCMD2", "Generic SCSI",
235                 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
236         return (0);
237 }
238
239 /*
240  * ---------------------------------------------------------------
241  * This routine sorts the amscsi_t lines on the following columns
242  * in ascending order:
243  *
244  *      1. drv  - driver name
245  *      2. bus  - scsibus per controller
246  *      3. tgt  - target id of device
247  *      4. lun  - lun of the device
248  *
249  */
250
251
252 static int
253 sort_mscsi(const void *l1, const void *l2)
254 {
255         amscsi_t        *t1 = (amscsi_t *) l1;
256         amscsi_t        *t2 = (amscsi_t *) l2;
257
258         if (strcmp(t1->drv, t2->drv) == 0) {
259                 if (t1->bus < t2->bus) {
260                         return (-1);
261
262                 } else if (t1->bus > t2->bus) {
263                         return (1);
264
265                 } else if (t1->tgt < t2->tgt) {
266                         return (-1);
267
268                 } else if (t1->tgt > t2->tgt) {
269                         return (1);
270
271                 } else if (t1->lun < t2->lun) {
272                         return (-1);
273
274                 } else if (t1->lun > t2->lun) {
275                         return (1);
276                 } else {
277                         return (0);
278                 }
279         } else {
280                 return (strcmp(t1->drv, t2->drv));
281         }
282 }
283
284 /*
285  * ---------------------------------------------------------------
286  * This routine is introduced to find all scsi devices which are
287  * currently configured into the kernel. This is done by reading
288  * the dynamic kernel mscsi tables and parse the resulting lines.
289  * As the output of 'sconf' is not directly usable the information
290  * found is to be sorted and re-arranged to be used with the libusal
291  * routines.
292  *
293  * NOTE: One problem is currently still not solved ! If you don't
294  *       have a media in your CD-ROM/CD-Writer we are not able to
295  *       do an open() and therefore will set the drive to be not
296  *       available (valid=0).
297  *
298  *       This will for example cause cdrecord to not list the drive
299  *       in the -scanbus output.
300  *
301  */
302
303 static int
304 openserver_init(SCSI *usalp)
305 {
306         FILE            *cmd;
307         int             nusal  = -1, lhba  = -1, lbus = -1;
308         int             nSrom = -1, nSdsk = -1, nStp = -1, nSflp = -1;
309         int             atapi, fd, nopen = 0;
310         int             pos = 0, len = 0, nlm = 0;
311         int             s = 0, t = 0, l = 0;
312         int             ide_rootdisk = 0;
313         long            dma_override = 0;
314         int             mscsi;
315         char            sconf[MAXLINE];
316         char            lines[MAXLINE];
317         char            drvid[MAXDRVN];
318         amscsi_t        cmtbl[MAXSCSI];
319         char            dname[MAXPATH];
320         char            **evsave;
321 extern  char            **environ;
322
323
324         for (s = 0; s < MAX_SCG; s++) {
325                 for (t = 0; t < MAX_TGT; t++) {
326                         for (l = 0; l < MAX_LUN; l++) {
327                                 sdidevs[s][t][l].valid  =  0;
328                                 sdidevs[s][t][l].open   = -1;
329                                 sdidevs[s][t][l].atapi  = -1;
330                                 sdidevs[s][t][l].fd     = -1;
331                                 sdidevs[s][t][l].lmscsi = -1;
332                         }
333                 }
334         }
335
336         /* Check whether we want to use the older SCSIUSERCMD ioctl() */
337
338         if (getenv(SCSI_USER_CMD) != NULL) {
339                 scsiusercmd = 1;
340         }
341
342         /*
343          * Check whether we want to scan all devices
344          */
345         if (getenv(SCAN_ALL) != NULL) {
346                 scan_all = 1;
347         }
348
349         /*
350          * Check whether we want to use USB devices
351          */
352         if (getenv(ENABLE_USB) != NULL) {
353                 enable_usb = 1;
354         }
355
356         /*
357          * Check whether we want to override the MAX_DMA value
358          */
359         if (getenv(DMA_OVERRIDE) != NULL) {
360                 dma_override = atol(getenv(DMA_OVERRIDE));
361                 if ((dma_override >= 1) && (dma_override <= (256)))
362                         max_dma = dma_override * 1024;
363         }
364
365
366         /* read sconf -r and get number of kernel mscsi lines ! */
367
368         evsave = environ;
369         environ = 0;
370         if ((cmd = popen(SCSI_CFG, "r")) == NULL) {
371                 if (usalp->errstr)
372                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
373                                 "Error popen() for \"%s\"",
374                                 SCSI_CFG);
375                 environ = evsave;
376                 return (-1);
377         }
378         environ = evsave;
379
380         if (fgets(lines, MAXLINE, cmd) == NULL) {
381                 errno = EIO;
382                 if (usalp->errstr)
383                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
384                                 "Error reading popen() for \"%s\"",
385                                 SCSI_CFG);
386                 return (-1);
387         } else
388                 nlm = atoi(lines);
389
390         if (usalp->debug > 0) {
391                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
392                 fprintf((FILE *)usalp->errfile, "mscsi lines = %d\n", nlm);
393                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
394         }
395
396         if (pclose(cmd) == -1) {
397                 if (usalp->errstr)
398                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
399                                 "Error pclose() for \"%s\"",
400                                 SCSI_CFG);
401                 return (-1);
402         }
403
404         for (l = 0; l < nlm; l++) {
405
406                 /* initialize cmtbl entry */
407
408                 cmtbl[l].hba = -1;
409                 cmtbl[l].bus = -1;
410                 cmtbl[l].tgt = -1;
411                 cmtbl[l].lun = -1;
412                 cmtbl[l].usal = -1;
413
414                 memset(cmtbl[l].typ, '\0', MAXDRVN);
415                 memset(cmtbl[l].drv, '\0', MAXDRVN);
416                 memset(cmtbl[l].dev, '\0', MAXDRVN);
417
418                 /* read sconf -g 'n' and get line of kernel mscsi table!  */
419                 /* the order the lines will be received in will determine */
420                 /* the device name we can use to open the device          */
421
422                 snprintf(sconf, sizeof (sconf),
423                         SCSI_DEV, l + 1); /* enumeration starts with 1 */
424
425                 evsave = environ;
426                 environ = 0;
427                 if ((cmd = popen(sconf, "r")) == NULL) {
428                         if (usalp->errstr)
429                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
430                                         "Error popen() for \"%s\"",
431                                         sconf);
432                         environ = evsave;
433                         return (-1);
434                 }
435                 environ = evsave;
436
437                 if (fgets(lines, MAXLINE, cmd) == NULL)
438                         break;
439
440                 if (pclose(cmd) == -1) {
441                         if (usalp->errstr)
442                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
443                                         "Error pclose() for \"%s\"",
444                                         sconf);
445                         return (-1);
446                 }
447
448                 sscanf(lines, SCAN_DEV, cmtbl[l].typ,
449                                         cmtbl[l].drv,
450                                         &cmtbl[l].hba,
451                                         &cmtbl[l].bus,
452                                         &cmtbl[l].tgt,
453                                         &cmtbl[l].lun);
454
455                 if (strstr(cmtbl[l].typ, T_DISK) != NULL) {
456                         snprintf(cmtbl[l].dev,  sizeof (cmtbl[l].dev),
457                                         DEV_SDSK, ++nSdsk);
458                 }
459
460                 if (strstr(cmtbl[l].typ, T_CDROM) != NULL) {
461                         snprintf(cmtbl[l].dev,  sizeof (cmtbl[l].dev),
462                                         DEV_SROM, ++nSrom);
463                 }
464
465                 if (strstr(cmtbl[l].typ, T_TAPE) != NULL) {
466                         snprintf(cmtbl[l].dev, sizeof (cmtbl[l].dev),
467                                         DEV_STP, ++nStp);
468                 }
469
470                 if (strstr(cmtbl[l].typ, T_FLOPPY) != NULL) {
471                         snprintf(cmtbl[l].dev, sizeof (cmtbl[l].dev),
472                                         DEV_SFLP, ++nSflp);
473                 }
474
475                 if (usalp->debug > 0) {
476                         fprintf((FILE *)usalp->errfile,
477                                 "%-4s = %5s(%d,%d,%d,%d) -> %s\n",
478                                 cmtbl[l].typ,
479                                 cmtbl[l].drv,
480                                 cmtbl[l].hba,
481                                 cmtbl[l].bus,
482                                 cmtbl[l].tgt,
483                                 cmtbl[l].lun,
484                                 cmtbl[l].dev);
485                 }
486
487         }
488
489         if (usalp->debug > 0) {
490                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
491                 fprintf((FILE *)usalp->errfile, "%2d DISK  \n", nSdsk + 1);
492                 fprintf((FILE *)usalp->errfile, "%2d CD-ROM\n", nSrom + 1);
493                 fprintf((FILE *)usalp->errfile, "%2d TAPE  \n", nStp  + 1);
494                 fprintf((FILE *)usalp->errfile, "%2d FLOPPY\n", nSflp + 1);
495                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
496         }
497
498         /* ok, now let's sort this array of scsi devices        */
499
500         qsort((void *) cmtbl, nlm, sizeof (amscsi_t), sort_mscsi);
501
502         if (usalp->debug > 0) {
503                 for (l = 0; l < nlm; l++)
504                 fprintf((FILE *)usalp->errfile,
505                         "%-4s = %5s(%d,%d,%d,%d) -> %s\n",
506                         cmtbl[l].typ,
507                         cmtbl[l].drv,
508                         cmtbl[l].hba,
509                         cmtbl[l].bus,
510                         cmtbl[l].tgt,
511                         cmtbl[l].lun,
512                         cmtbl[l].dev);
513                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
514         }
515
516         /* find root disk controller to make it usal 0          */
517
518         /*
519          * if we have disk(s) found in the mscsi table, we still
520          * don't know if the rootdisk is among these, there can
521          * be a IDE rootdisk as well, but it's not listed in
522          * the mscsi table.
523          */
524
525         t = 0;
526         if (nSdsk > 0) {
527                 for (l = 0; l < nlm; l++)
528                         if (strcmp(cmtbl[l].dev, DEV_ROOT) == 0)
529                                 t = l;
530         } else {
531
532                 /*
533                  * we haven't found a disk in mscsi, so we definitely
534                  * have an IDE disk on a wd adapter as IDE disks are
535                  * not listed as SCSI disks in the kernel mscsi table
536                  */
537                 ide_rootdisk = 1;
538
539         }
540
541         if (!(ide_rootdisk) && (usalp->debug > 0)) {
542                 fprintf((FILE *)usalp->errfile,
543                         "root = %5s(%d,%d,%d,%d) -> %s\n",
544                         cmtbl[t].drv,
545                         cmtbl[t].hba,
546                         cmtbl[t].bus,
547                         cmtbl[t].tgt,
548                         cmtbl[t].lun,
549                         cmtbl[t].dev);
550                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
551         }
552
553         /* calculate usal from drv, hba and bus                         */
554
555         strcpy(drvid, "");
556
557         for (l = 0, s = t; l < nlm; l++, s = (t + l) % nlm) {
558
559                 if (strcmp(drvid, cmtbl[s].drv) != 0) {
560                         strcpy(drvid, cmtbl[s].drv);
561                         lhba = cmtbl[s].hba;
562                         lbus = cmtbl[s].bus;
563                         cmtbl[s].usal = ++nusal;
564
565                 } else if (cmtbl[s].hba != lhba) {
566                         lhba = cmtbl[s].hba;
567                         lbus = cmtbl[s].bus;
568                         cmtbl[s].usal = ++nusal;
569
570                 } else if (cmtbl[s].bus != lbus) {
571                         lbus = cmtbl[s].bus;
572                         cmtbl[s].usal = ++nusal;
573                 } else {
574                         cmtbl[s].usal = nusal;
575                 }
576                 sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].open   = 0;
577
578                 /* check whether we want to open all devices or it's a CDROM */
579
580                 if ((scan_all) || (strcmp(cmtbl[s].typ, T_CDROM) == 0))
581                         sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].valid = 1;
582
583                 /* check whether we have an IDE/ATAPI device */
584
585                 if (strcmp(cmtbl[s].drv, DRV_ATAPI) == 0)
586                         sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].atapi = 1;
587
588                 /* don't open a USB device if enable_usb is not set */
589
590                 if (strcmp(cmtbl[s].drv, DRV_USB) == 0)
591                         sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].valid = enable_usb;
592
593                 /* don't open a IDE/ATAPI device which is missing but configured */
594
595                 if (strcmp(cmtbl[s].drv, DRV_NOHA) == 0)
596                         sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].valid = 0;
597
598
599                 sdidevs[cmtbl[s].usal][cmtbl[s].tgt][cmtbl[s].lun].lmscsi = s;
600
601         }
602
603
604         /* open all yet valid device nodes */
605
606         for (s = 0; s < MAX_SCG; s++) {
607                 for (t = 0; t < MAX_TGT; t++) {
608                         for (l = 0; l < MAX_LUN; l++) {
609
610                                 if (sdidevs[s][t][l].valid == 0)
611                                         continue;
612
613                                 /* Open pass-through device node */
614
615                                 mscsi = sdidevs[s][t][l].lmscsi;
616
617                                 strcpy(dname, cmtbl[mscsi].dev);
618
619         /*
620          * ------------------------------------------------------------------
621          * NOTE: If we can't open the device, we will set the device invalid!
622          * ------------------------------------------------------------------
623          */
624                                 errno = 0;
625                                 if ((fd = open(dname, (O_RDONLY | O_NONBLOCK))) < 0) {
626                                         sdidevs[s][t][l].valid = 0;
627                                         if (usalp->debug > 0) {
628                                                 fprintf((FILE *)usalp->errfile,
629                                                         "%5s(%d,%d,%d,%d) -> %s open() failed: errno = %d (%s)\n",
630                                                         cmtbl[mscsi].drv,
631                                                         cmtbl[mscsi].hba,
632                                                         cmtbl[mscsi].bus,
633                                                         cmtbl[mscsi].tgt,
634                                                         cmtbl[mscsi].lun,
635                                                         cmtbl[mscsi].dev,
636                                                         errno,
637                                                         strerror(errno));
638                                         }
639                                         continue;
640                                 }
641
642                                 if (usalp->debug > 0) {
643                                         fprintf((FILE *)usalp->errfile,
644                                                 "%d,%d,%d => %5s(%d,%d,%d,%d) -> %d : %s \n",
645                                                 s, t, l,
646                                                 cmtbl[mscsi].drv,
647                                                 cmtbl[mscsi].hba,
648                                                 cmtbl[mscsi].bus,
649                                                 cmtbl[mscsi].tgt,
650                                                 cmtbl[mscsi].lun,
651                                                 cmtbl[mscsi].usal,
652                                                 cmtbl[mscsi].dev);
653                                 }
654
655                                 sdidevs[s][t][l].fd   = fd;
656                                 sdidevs[s][t][l].open = 1;
657                                 nopen++;
658                                 usallocal(usalp)->usalfiles[s][t][l] = (short) fd;
659                         }
660                 }
661         }
662
663         if (usalp->debug > 0) {
664                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
665                 fprintf((FILE *)usalp->errfile, "nopen = %d devices   \n", nopen);
666                 fprintf((FILE *)usalp->errfile, "-------------------- \n");
667         }
668
669         return (nopen);
670 }
671
672
673 static int
674 usalo_open(SCSI *usalp, char *device)
675 {
676         int     busno   = usal_scsibus(usalp);
677         int     tgt     = usal_target(usalp);
678         int     tlun    = usal_lun(usalp);
679         int     f, b, t, l;
680         int     nopen = 0;
681         char    devname[64];
682
683         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
684                 errno = EINVAL;
685                 if (usalp->errstr)
686                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
687                                 "Illegal value for busno, target or lun '%d,%d,%d'",
688                                 busno, tgt, tlun);
689                 return (-1);
690         }
691
692         if (usalp->local == NULL) {
693                 usalp->local = malloc(sizeof (struct usal_local));
694                 if (usalp->local == NULL)
695                         return (0);
696
697                 for (b = 0; b < MAX_SCG; b++) {
698                         for (t = 0; t < MAX_TGT; t++) {
699                                 for (l = 0; l < MAX_LUN; l++)
700                                         usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
701                         }
702                 }
703         }
704
705         if (*device != '\0') {          /* we don't allow old dev usage */
706                 errno = EINVAL;
707                 if (usalp->errstr)
708                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
709                         "Open by 'devname' no longer supported on this OS");
710                 return (-1);
711         }
712
713         return (openserver_init(usalp));
714
715 }
716
717 static int
718 usalo_close(SCSI *usalp)
719 {
720         register int    f;
721         register int    b;
722         register int    t;
723         register int    l;
724
725         if (usalp->local == NULL)
726                 return (-1);
727
728         for (b = 0; b < MAX_SCG; b++) {
729                 for (t = 0; t < MAX_TGT; t++) {
730                         for (l = 0; l < MAX_LUN; l++) {
731
732                                 f = usallocal(usalp)->usalfiles[b][t][l];
733                                 if (f >= 0)
734                                         close(f);
735
736                                 sdidevs[b][t][l].fd    = -1;
737                                 sdidevs[b][t][l].open  =  0;
738                                 sdidevs[b][t][l].valid =  0;
739
740                                 usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
741                         }
742                 }
743         }
744         return (0);
745 }
746
747 static long
748 usalo_maxdma(SCSI *usalp, long amt)
749 {
750         return (max_dma);
751 }
752
753
754 static void *
755 usalo_getbuf(SCSI *usalp, long amt)
756 {
757         if (usalp->debug > 0) {
758                 fprintf((FILE *)usalp->errfile,
759                         "usalo_getbuf: %ld bytes\n", amt);
760         }
761         usalp->bufbase = valloc((size_t)(amt));
762
763         return (usalp->bufbase);
764 }
765
766 static void
767 usalo_freebuf(SCSI *usalp)
768 {
769         if (usalp->bufbase)
770                 free(usalp->bufbase);
771         usalp->bufbase = NULL;
772 }
773
774 static BOOL
775 usalo_havebus(SCSI *usalp, int busno)
776 {
777         register int    t;
778         register int    l;
779
780         if (busno < 0 || busno >= MAX_SCG)
781                 return (FALSE);
782
783         if (usalp->local == NULL)
784                 return (FALSE);
785
786         for (t = 0; t < MAX_TGT; t++) {
787                 for (l = 0; l < MAX_LUN; l++)
788                         if (usallocal(usalp)->usalfiles[busno][t][l] >= 0)
789                                 return (TRUE);
790         }
791         return (FALSE);
792 }
793
794 static int
795 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
796 {
797         if (busno < 0 || busno >= MAX_SCG ||
798             tgt   < 0 || tgt   >= MAX_TGT ||
799             tlun  < 0 || tlun  >= MAX_LUN)
800                 return (-1);
801
802         if (usalp->local == NULL)
803                 return (-1);
804
805         return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]);
806 }
807
808 static int
809 usalo_initiator_id(SCSI *usalp)
810 {
811         return (-1);
812
813         /*
814          * We don't know the initiator ID yet, but we can if we parse the
815          * output of the command 'cat /dev/string/cfg | grep "%adapter"'
816          *
817          * Sample line:
818          *
819          *      %adapter 0xE800-0xE8FF 11 - type=alad ha=0 bus=0 id=7 fts=sto
820          *
821          * This tells us that the alad controller 0 has an id of 7 !
822          * The parsing should be done in openserver_init().
823          *
824          */
825 }
826
827 static int
828 usalo_isatapi(SCSI *usalp)
829 {
830         return (sdidevs[usal_scsibus(usalp)][usal_target(usalp)][usal_lun(usalp)].atapi);
831 }
832
833 static int
834 usalo_reset(SCSI *usalp, int what)
835 {
836         errno = EINVAL;
837         return (-1);            /* no scsi reset available */
838 }
839
840 static void
841 cp_usal2sco(struct scsicmd2 *sco, struct usal_cmd *usal)
842 {
843         sco->cmd.data_ptr = (char *) usal->addr;
844         sco->cmd.data_len = usal->size;
845         sco->cmd.cdb_len  = usal->cdb_len;
846
847         sco->sense_len    = usal->sense_len;
848         sco->sense_ptr    = usal->u_sense.cmd_sense;
849
850         if (!(usal->flags & SCG_RECV_DATA) && (usal->size > 0))
851                 sco->cmd.is_write = 1;
852
853         if (usal->cdb_len == SC_G0_CDBLEN)
854                 memcpy(sco->cmd.cdb, &usal->cdb.g0_cdb, usal->cdb_len);
855
856         if (usal->cdb_len == SC_G1_CDBLEN)
857                 memcpy(sco->cmd.cdb, &usal->cdb.g1_cdb, usal->cdb_len);
858
859         if (usal->cdb_len == SC_G5_CDBLEN)
860                 memcpy(sco->cmd.cdb, &usal->cdb.g5_cdb, usal->cdb_len);
861 }
862
863
864 static void
865 cp_sco2usal(struct scsicmd2 *sco, struct usal_cmd *usal)
866 {
867         usal->size      = sco->cmd.data_len;
868
869         memset(&usal->scb, 0, sizeof (usal->scb));
870
871         if (sco->sense_len > SCG_MAX_SENSE)
872                 usal->sense_count = SCG_MAX_SENSE;
873         else
874                 usal->sense_count = sco->sense_len;
875
876         usal->resid = 0;
877
878         usal->u_scb.cmd_scb[0] = sco->cmd.target_sts;
879
880 }
881
882
883 static int
884 usalo_send(SCSI *usalp)
885 {
886         struct usal_cmd *sp = usalp->scmd;
887         struct scsicmd2 scsi_cmd;
888         int             i;
889         Uchar           sense_buf[SCG_MAX_SENSE];
890
891         if (usalp->fd < 0) {
892                 sp->error = SCG_FATAL;
893                 return (0);
894         }
895
896         memset(&scsi_cmd, 0, sizeof (scsi_cmd));
897         memset(sense_buf, 0, sizeof (sense_buf));
898         scsi_cmd.sense_ptr = sense_buf;
899         scsi_cmd.sense_len = sizeof (sense_buf);
900         cp_usal2sco(&scsi_cmd, sp);
901
902         errno = 0;
903         sp->ux_errno = 0;
904         sp->error = SCG_NO_ERROR;
905         for (;;) {
906                 int             ioctlStatus;
907                 struct scsicmd  s_cmd;
908
909                 if (scsiusercmd) {      /* Use SCSIUSERCMD ioctl() */
910                         if (usalp->debug > 1) {
911                                 fprintf((FILE *)usalp->errfile, "calling SCSIUSERCMD ioctl()\n");
912                         }
913
914                         if ((ioctlStatus = ioctl(usalp->fd, SCSIUSERCMD, &(scsi_cmd.cmd))) < 0) {
915                                 if (usalp->debug > 1) {
916                                         fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD ioctl()\n");
917                                 }
918                                 if (errno == EINTR)
919                                         continue;
920
921                                 cp_sco2usal(&scsi_cmd, sp);
922                                 sp->ux_errno = errno;
923                                 if (errno == 0)
924                                         sp->ux_errno = EIO;
925                                 sp->error    = SCG_RETRYABLE;
926
927                                 return (0);
928                         }
929
930                         if (usalp->debug > 1) {
931                                 fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD ioctl()\n");
932                         }
933                         cp_sco2usal(&scsi_cmd, sp);
934                         sp->ux_errno = errno;
935
936                         if (scsi_cmd.cmd.target_sts & 0x02) { /* Check Condition & get Sense */
937
938                                 if (sp->sense_len > SCG_MAX_SENSE)
939                                         sp->sense_len = SCG_MAX_SENSE;
940
941                                 memset((caddr_t)&s_cmd, 0, sizeof (s_cmd));
942
943                                 s_cmd.data_ptr  = (caddr_t) sp->u_sense.cmd_sense;
944                                 s_cmd.data_len  = sp->sense_len;
945                                 s_cmd.is_write  = 0;
946                                 s_cmd.cdb[0]    = SC_REQUEST_SENSE;
947
948                                 while (((ioctlStatus = ioctl(usalp->fd, SCSIUSERCMD, &s_cmd)) < 0) &&
949                                         (errno == EINTR))
950                                                 ;
951
952                                 sp->sense_count = sp->sense_len;
953                                 sp->ux_errno    = errno;
954
955                                 if (errno == 0)
956                                         sp->ux_errno = EIO;
957                                 sp->error = SCG_NO_ERROR;
958                         }
959
960                         if (usalp->debug > 0) {
961                                 if (errno != 0)
962                                         fprintf((FILE *)usalp->errfile, "ux_errno: %d (%s) \n", sp->ux_errno, strerror(sp->ux_errno));
963                                 if (sp->u_scb.cmd_scb[0] != 0)
964                                         fprintf((FILE *)usalp->errfile, "tgt_stat: %d \n", sp->u_scb.cmd_scb[0]);
965                         }
966                         break;
967
968                 } else {                /* Use SCSIUSERCMD2 ioctl() */
969                         if (usalp->debug > 1) {
970                                 fprintf((FILE *)usalp->errfile, "calling SCSIUSERCMD2 ioctl()\n");
971                         }
972
973                         if ((ioctlStatus = ioctl(usalp->fd, SCSIUSERCMD2, &scsi_cmd)) < 0) {
974                                 if (usalp->debug > 1) {
975                                         fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD2 ioctl()\n");
976                                 }
977                                 if (errno == EINTR)
978                                         continue;
979
980                                 cp_sco2usal(&scsi_cmd, sp);
981                                 sp->ux_errno = errno;
982                                 if (errno == 0)
983                                         sp->ux_errno = EIO;
984                                 sp->error    = SCG_RETRYABLE;
985
986                                 return (0);
987                         }
988                         if (usalp->debug > 1) {
989                                 fprintf((FILE *)usalp->errfile, "returning from SCSIUSERCMD2 ioctl()\n");
990                         }
991
992                         cp_sco2usal(&scsi_cmd, sp);
993                         sp->ux_errno = errno;
994
995                         if (scsi_cmd.cmd.target_sts & 0x02) { /* Check Condition */
996                                 if (errno == 0)
997                                         sp->ux_errno = EIO;
998                                 sp->error    = SCG_NO_ERROR;
999                         }
1000
1001                         if (usalp->debug > 0) {
1002                                 if (errno != 0)
1003                                         fprintf((FILE *)usalp->errfile, "ux_errno: %d (%s) \n", sp->ux_errno, strerror(sp->ux_errno));
1004                                 if (sp->u_scb.cmd_scb[0] != 0)
1005                                         fprintf((FILE *)usalp->errfile, "tgt_stat: %d \n", sp->u_scb.cmd_scb[0]);
1006                         }
1007                         break;
1008
1009                 }
1010         }
1011
1012         return (0);
1013 }
1014
1015 #define sense   u_sense.Sense