Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-unixware.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-unixware.c  1.36 04/01/15 Copyright 1998 J. Schilling, Santa Cruz Operation */
14 /*
15  *      Interface for the SCO UnixWare 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 #undef  SC_PARITY
42 #undef  scb
43
44 #include <sys/sysmacros.h>      /* XXX Falsch, richtig -> sys/mkdev.h */
45 #include <sys/scsi.h>
46 #include <sys/sdi_edt.h>
47 #include <sys/sdi.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-unixware.c-1.36"; /* The version for this transport*/
57
58 /* Max. number of usal scsibusses.  The real limit would be             */
59 /* MAX_HBA * MAX_BUS (which would be 32 * 8 on UnixWare 2.1/7.x),       */
60 /* but given that we will hardly see such a beast, lets take 32         */
61
62 #define MAX_SCG         32
63
64         /* maximum defines for UnixWare 2.x/7.x from <sys/sdi_edt.h> */
65
66 #define MAX_TGT         MAX_EXTCS       /* Max # of target id's         */
67 #define MAX_LUN         MAX_EXLUS       /* Max # of lun's               */
68
69 #define MAX_DMA         (32*1024)
70 #ifdef  __WHAT_TODO__
71 #define MAX_DMA         (16*1024)       /* On UnixWare 2.1.x w/ AHA2940 HBA */
72                                         /* the max DMA size is 16KB.        */
73 #endif
74
75 #define MAXLINE         80
76 #define MAXPATH         256
77
78 #define DEV_DIR         "/tmp"
79 #define DEV_NAME        "usal.s%1dt%1dl%1d"
80
81 #define SCAN_HBA        "%d:%d,%d,%d:%7s : %n"
82 #define SCAN_DEV        "%d,%d,%d:%7s : %n"
83
84 #define PRIM_HBA        "/dev/hba/hba1"
85 #define SCSI_CFG        "LC_ALL=C /etc/scsi/pdiconfig -l"
86
87 #define SCAN_ALL        "LIBSCG_SCAN_ALL"
88
89 #define SDI_VALID       0x01    /* Entry may be used (non disk)    */
90 #define SDI_ATAPI       0x02    /* Connected via IDE HBA           */
91 #define SDI_INITIATOR   0x04    /* This is the initiator target ID */
92
93 typedef struct usal2sdi {
94         short   open;
95         short   flags;
96         short   fd;
97         char    hba;
98         char    bus;
99         char    tgt;
100         char    lun;
101
102         dev_t   node;
103         dev_t   major;
104         dev_t   minor;
105 /*#define       SCG_DEBUG*/
106 #ifdef  SCG_DEBUG
107         char    type[20];
108         char    vend[40];
109         char    devn[32];
110 #endif
111 } usal2sdi_t;
112
113 static  usal2sdi_t      sdidevs [MAX_SCG][MAX_TGT][MAX_LUN];
114 static  BOOL            sdiinit = FALSE;
115
116 struct usal_local {
117         short   usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
118 };
119 #define usallocal(p)    ((struct usal_local *)((p)->local))
120
121 static  int     unixware_init(SCSI *usalp);
122 static  int     do_usal_cmd(SCSI *usalp, struct usal_cmd *sp);
123 static  int     do_usal_sense(SCSI *usalp, struct usal_cmd *sp);
124 static  FILE    *xpopen(char *cmd, char *type);
125 static  int     xpclose(FILE *f);
126
127 /*
128  * -------------------------------------------------------------------------
129  * SCO UnixWare 2.1.x / UnixWare 7 provides a scsi pass-through mechanism,
130  * which can be used to access any configured scsi device.
131  *
132  * NOTE: The libusal UnixWare passthrough routines have changed with
133  *       cdrecord-1.8 to enable the -scanbus, -load, -eject option
134  *       regardless of the status of media and the addressing
135  *       scheme is now the same as used on many other platforms like
136  *       Solaris, Linux etc.
137  *
138  *      ===============================================================
139  *      RUN 'cdrecord -scanbus' TO SEE THE DEVICE ADDRESSES YOU CAN USE
140  *      ===============================================================
141  */
142
143 /*
144  * Return version information for the low level SCSI transport code.
145  * This has been introduced to make it easier to trace down problems
146  * in applications.
147  *
148  */
149 static char *
150 usalo_version(SCSI *usalp, int what)
151 {
152         if (usalp != (SCSI *)0) {
153                 switch (what) {
154
155                 case SCG_VERSION:
156                         return (_usal_trans_version);
157                 /*
158                  * If you changed this source, you are not allowed to
159                  * return "schily" for the SCG_AUTHOR request.
160                  */
161                 case SCG_AUTHOR:
162                         return (_usal_auth_cdrkit);
163                 case SCG_SCCS_ID:
164                         return (__sccsid);
165                 }
166         }
167         return ((char *)0);
168 }
169
170
171 static int
172 usalo_help(SCSI *usalp, FILE *f)
173 {
174         __usal_help(f, "SDI_SEND", "Generic SCSI",
175                 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
176         return (0);
177 }
178
179 /*
180  * ---------------------------------------------------------------
181  * This routine is introduced to create all device nodes necessary
182  * to access any detected scsi device. It parses the output of
183  * /etc/scsi/pdiconfig -l and creates passthru device node for each
184  * found scsi device apart from the listed hba's.
185  *
186  */
187
188 static int
189 unixware_init(SCSI *usalp)
190 {
191         FILE            *cmd;
192         int             hba = 0, bus = 0, usal = 0, tgt = 0, lun = 0;
193         int             nusal = -1, lhba = -1, lbus = 0;
194         int             atapi, fd, nopen = 0, pos = 0, len = 0;
195         int             s, t, l;
196         int             scan_disks;
197         char            lines[MAXLINE];
198         char            class[MAXLINE];
199         char            ident[MAXLINE];
200         char            devnm[MAXPATH];
201         char            dname[MAXPATH];
202         struct stat     stbuf;
203         dev_t           ptdev, major, minor, node;
204         char            **evsave;
205 extern  char            **environ;
206
207         /* Check for validity of primary hostbus adapter node */
208
209         if (stat(PRIM_HBA, &stbuf) < 0) {
210                 if (usalp->errstr)
211                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
212                                 "Can not stat() primary hba (%s)",
213                                 PRIM_HBA);
214                 return (-1);
215         }
216
217         if (!S_ISCHR(stbuf.st_mode)) {
218                 if (usalp->errstr)
219                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
220                                 "Primary hba (%s) not a character device",
221                                 PRIM_HBA);
222                 return (-1);
223         }
224
225         major = getmajor(stbuf.st_rdev);
226
227         /*
228          * Check whether we want to scan all devices
229          */
230         if (getenv(SCAN_ALL) != NULL) {
231                 scan_disks = 1;
232         } else {
233                 scan_disks = 0;
234         }
235
236         /* read pdiconfig output and get all attached scsi devices ! */
237
238         evsave = environ;
239         environ = 0;
240         if ((cmd = xpopen(SCSI_CFG, "r")) == NULL) {
241                 if (usalp->errstr)
242                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
243                                 "Error popen() for \"%s\"",
244                                 SCSI_CFG);
245                 environ = evsave;
246                 return (-1);
247         }
248         environ = evsave;
249
250
251         for (;;) {
252                 if (fgets(lines, MAXLINE, cmd) == NULL)
253                         break;
254
255                 memset(class, '\0', sizeof (class));
256                 memset(ident, '\0', sizeof (ident));
257
258                 if (lines[0] == ' ') {
259                         sscanf(lines, SCAN_DEV, &bus, &tgt, &lun, class, &pos);
260                         hba = lhba;
261                 } else {
262                         sscanf(lines, SCAN_HBA, &hba, &bus, &tgt, &lun, class, &pos);
263                         nusal++;
264                         lhba = hba;
265                         atapi = 0;
266                 }
267
268                 /* We can't sscanf() the ident string of the device     */
269                 /* as it may contain characters sscanf() will           */
270                 /* recognize as a delimiter. So do a strcpy() instead ! */
271
272                 len = strlen(lines) - pos - 1; /* don't copy the '\n' */
273
274                 strncpy(ident, &lines[pos], len);
275
276                 if (usalp->debug > 0) {
277                         fprintf((FILE *)usalp->errfile,
278                                 "SDI -> %d:%d,%d,%d: %-7s : %s\n",
279                                 hba, bus, tgt, lun, class, ident);
280                 }
281                 if (bus != lbus) {
282                         nusal++;
283                         lbus = bus;
284                 }
285
286                 usal = nusal;
287
288                 /* check whether we have a HBA or a SCSI device, don't  */
289                 /* let HBA's be valid device for cdrecord, but mark     */
290                 /* them as a controller (initiator = 1).                */
291
292                 /* Don't detect disks, opening a mounted disk can hang  */
293                 /* the disk subsystem !!! So unless we set an           */
294                 /* environment variable LIBSCG_SCAN_ALL, we will ignore */
295                 /* disks                                                */
296
297                 if (strstr(class, "HBA") == NULL) {
298                         if (strstr(class, "DISK") != NULL) {
299                                 if (scan_disks)
300                                         sdidevs[usal][tgt][lun].flags |= SDI_VALID;
301                                 else
302                                         sdidevs[usal][tgt][lun].flags &= ~SDI_VALID;
303                         } else {
304                                 sdidevs[usal][tgt][lun].flags |= SDI_VALID;
305                         }
306                 } else {
307                         sdidevs[usal][tgt][lun].flags |= SDI_INITIATOR;
308                 }
309
310
311                 /* There is no real flag that shows a HBA as an ATAPI   */
312                 /* controller, so as we know the driver is called 'ide' */
313                 /* we can check the ident string for the occurence of it*/
314
315                 if (strstr(ident, "(ide,") != NULL) {
316                         atapi = 1;
317                 }
318
319                 /*
320                  * Fill the sdidevs array with all we know now.
321                  * Do not overwrite fields that may contain old state like
322                  * sdidevs[usal][tgt][lun].open
323                  */
324
325                 if (atapi)
326                         sdidevs[usal][tgt][lun].flags |= SDI_ATAPI;
327                 else
328                         sdidevs[usal][tgt][lun].flags &= ~SDI_ATAPI;
329
330                 sdidevs[usal][tgt][lun].hba = hba;
331                 sdidevs[usal][tgt][lun].bus = bus;
332                 sdidevs[usal][tgt][lun].tgt = tgt;
333                 sdidevs[usal][tgt][lun].lun = lun;
334
335 #ifdef  SCG_DEBUG
336                 strcpy(sdidevs[usal][tgt][lun].type, class);
337                 strcpy(sdidevs[usal][tgt][lun].vend, ident);
338
339                 snprintf(sdidevs[usal][tgt][lun].devn,
340                                 sizeof (sdidevs[usal][tgt][lun].devn),
341                                 DEV_NAME, usal, tgt, lun);
342 #endif
343                 snprintf(devnm, sizeof (devnm),
344                                 DEV_NAME, usal, tgt, lun);
345
346                 minor = SDI_MINOR(hba, tgt, lun, bus);
347                 node  = makedevice(major, minor);
348
349                 sdidevs[usal][tgt][lun].major = major;
350                 sdidevs[usal][tgt][lun].minor = minor;
351                 sdidevs[usal][tgt][lun].node  = node;
352
353                 if (usalp->debug > 0) {
354
355                         fprintf((FILE *)usalp->errfile,
356                         "h = %d; b = %d, s = %d, t = %d, l = %d, a = %d, ma = %d, mi = %2d, dev = '%s', id = '%s'\n",
357                         hba, bus, usal, tgt, lun,
358                         (sdidevs[usal][tgt][lun].flags & SDI_ATAPI) != 0,
359                         sdidevs[usal][tgt][lun].major,
360                         sdidevs[usal][tgt][lun].minor,
361                         devnm,
362                         ident);
363                 }
364
365
366         }
367
368         if (xpclose(cmd) == -1) {
369                 if (usalp->errstr)
370                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
371                                 "Error pclose() for \"%s\"",
372                                 SCSI_CFG);
373                 return (-1);
374         }
375
376
377         /* create all temporary device nodes */
378
379         for (s = 0; s < MAX_SCG; s++) {
380                 for (t = 0; t < MAX_TGT; t++) {
381                         for (l = 0; l < MAX_LUN; l++) {
382
383                                 if ((sdidevs[s][t][l].flags & SDI_VALID) == 0) {
384                                         if (sdidevs[s][t][l].fd >= 0) {
385                                                 close(sdidevs[s][t][l].fd);
386                                         }
387                                         sdidevs[s][t][l].fd = -1;
388                                         sdidevs[s][t][l].open = 0;
389                                         continue;
390                                 }
391
392                                 /* Make pass-through interface device node */
393
394                                 snprintf(devnm,
395                                         sizeof (devnm),
396                                         DEV_NAME, s, t, l);
397
398                                 snprintf(dname, sizeof (dname),
399                                         "%s/%s", DEV_DIR, devnm);
400
401                                 ptdev = sdidevs[s][t][l].node;
402
403                                 if (mknod(dname, S_IFCHR | 0700, ptdev) < 0) {
404                                         if (errno == EEXIST) {
405                                                 unlink(dname);
406
407                                                 if (mknod(dname, S_IFCHR | 0700, ptdev) < 0) {
408                                                         if (usalp->errstr)
409                                                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
410                                                                         "mknod() error for \"%s\"", dname);
411                                                         return (-1);
412                                                 }
413                                         } else {
414                                                 if (usalp->errstr)
415                                                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
416                                                                 "mknod() error for \"%s\"", dname);
417                                                 return (-1);
418                                         }
419                                 }
420
421                                 /* Open pass-through device node */
422
423                                 if ((fd = open(dname, O_RDONLY)) < 0) {
424                                         if (errno == EBUSY && sdidevs[s][t][l].open > 0) {
425                                                 /*
426                                                  * Device has already been opened, just
427                                                  * return the saved file desc.
428                                                  */
429                                                 fd = sdidevs[s][t][l].fd;
430                                         } else {
431                                                 if (usalp->errstr)
432                                                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
433                                                                 "can not open pass-through %s", dname);
434                                                 return (-1);
435                                         }
436                                 }
437
438                                 /*
439                                  * If for whatever reason we may open a pass through
440                                  * device more than once, this will waste fs's as we
441                                  * do not check for sdidevs[s][t][l].fd == -1.
442                                  */
443                                 sdidevs[s][t][l].fd   = fd;
444                                 sdidevs[s][t][l].open++;
445                                 nopen++;
446                                 usallocal(usalp)->usalfiles[s][t][l] = (short) fd;
447
448                                 if (usalp->debug > 0) {
449
450                                         fprintf((FILE *)usalp->errfile,
451                                                 "s = %d, t = %d, l = %d, dev = %s, fd = %d\n",
452                                                 s, t, l,
453                                                 devnm,
454                                                 sdidevs[s][t][l].fd);
455                                 }
456
457                         }
458                 }
459         }
460
461         return (nopen);
462 }
463
464
465 static int
466 usalo_open(SCSI *usalp, char *device)
467 {
468         int     busno   = usal_scsibus(usalp);
469         int     tgt     = usal_target(usalp);
470         int     tlun    = usal_lun(usalp);
471         int     b, t, l;
472
473         if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
474                 errno = EINVAL;
475                 if (usalp->errstr)
476                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
477                                 "Illegal value for busno, target or lun '%d,%d,%d'",
478                                 busno, tgt, tlun);
479                 return (-1);
480         }
481
482         if (usalp->local == NULL) {
483                 usalp->local = malloc(sizeof (struct usal_local));
484                 if (usalp->local == NULL)
485                         return (0);
486
487                 for (b = 0; b < MAX_SCG; b++) {
488                         for (t = 0; t < MAX_TGT; t++) {
489                                 for (l = 0; l < MAX_LUN; l++)
490                                         usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
491                         }
492                 }
493         }
494
495         if (!sdiinit) {
496                 sdiinit = TRUE;
497                 memset(sdidevs, 0, sizeof (sdidevs));   /* init tmp_structure */
498                 for (b = 0; b < MAX_SCG; b++) {
499                         for (t = 0; t < MAX_TGT; t++) {
500                                 for (l = 0; l < MAX_LUN; l++) {
501
502                                         sdidevs[b][t][l].flags = 0;
503                                         sdidevs[b][t][l].fd = -1;
504                                         sdidevs[b][t][l].open = 0;
505                                 }
506                         }
507                 }
508         }
509
510         if (*device != '\0') {          /* we don't allow old dev usage */
511                 errno = EINVAL;
512                 if (usalp->errstr)
513                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
514                         "Open by 'devname' no longer supported on this OS");
515                 return (-1);
516         } else {                        /* this is the new stuff         */
517                                         /* it will do the initialisation */
518                                         /* and return the number of      */
519                                         /* detected devices to be used   */
520                                         /* with the new addressing       */
521                                         /* scheme.                       */
522
523                 return (unixware_init(usalp));
524         }
525
526 }
527
528
529 static int
530 usalo_close(SCSI *usalp)
531 {
532         register int    f;
533         register int    b;
534         register int    t;
535         register int    l;
536
537         if (usalp->local == NULL)
538                 return (-1);
539
540         for (b = 0; b < MAX_SCG; b++) {
541                 for (t = 0; t < MAX_TGT; t++) {
542                         for (l = 0; l < MAX_LUN; l++) {
543
544                                 f = usallocal(usalp)->usalfiles[b][t][l];
545                                 if (f >= 0) {
546                                         if (sdidevs[b][t][l].open > 0)
547                                                 sdidevs[b][t][l].open--;
548                                         if (sdidevs[b][t][l].open <= 0) {
549                                                 if (sdidevs[b][t][l].fd >= 0)
550                                                         close(sdidevs[b][t][l].fd);
551                                                 sdidevs[b][t][l].fd    = -1;
552                                                 sdidevs[b][t][l].flags &= ~SDI_VALID;
553                                         }
554                                 }
555                                 usallocal(usalp)->usalfiles[b][t][l] = (short)-1;
556                         }
557                 }
558         }
559         return (0);
560 }
561
562 static long
563 usalo_maxdma(SCSI *usalp, long amt)
564 {
565         return (MAX_DMA);
566 }
567
568
569 static void *
570 usalo_getbuf(SCSI *usalp, long amt)
571 {
572         if (usalp->debug > 0) {
573                 fprintf((FILE *)usalp->errfile,
574                         "usalo_getbuf: %ld bytes\n", amt);
575         }
576         usalp->bufbase = (void *) valloc((size_t)(amt));
577
578         return (usalp->bufbase);
579 }
580
581 static void
582 usalo_freebuf(SCSI *usalp)
583 {
584         if (usalp->bufbase)
585                 free(usalp->bufbase);
586         usalp->bufbase = NULL;
587 }
588
589 static BOOL
590 usalo_havebus(SCSI *usalp, int busno)
591 {
592         register int    t;
593         register int    l;
594
595         if (busno < 0 || busno >= MAX_SCG)
596                 return (FALSE);
597
598         if (usalp->local == NULL)
599                 return (FALSE);
600
601         for (t = 0; t < MAX_TGT; t++) {
602                 for (l = 0; l < MAX_LUN; l++)
603                         if (usallocal(usalp)->usalfiles[busno][t][l] >= 0)
604                                 return (TRUE);
605         }
606         return (FALSE);
607 }
608
609 static int
610 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
611 {
612         if (busno < 0 || busno >= MAX_SCG ||
613             tgt   < 0 || tgt   >= MAX_TGT ||
614             tlun  < 0 || tlun  >= MAX_LUN)
615                 return (-1);
616
617         if (usalp->local == NULL)
618                 return (-1);
619
620         return ((int)usallocal(usalp)->usalfiles[busno][tgt][tlun]);
621 }
622
623 static int
624 usalo_initiator_id(SCSI *usalp)
625 {
626         register int    t;
627         register int    l;
628         register int    busno;
629
630         busno = usal_scsibus(usalp);
631
632         if (busno < 0 || busno >= MAX_SCG)
633                 return (FALSE);
634
635         for (t = 0; t < MAX_TGT; t++) {
636                 for (l = 0; l < MAX_LUN; l++)
637                         if ((sdidevs[busno][t][l].flags & SDI_INITIATOR) != 0) {
638                                 if (usalp->debug > 0) {
639                                         fprintf((FILE *)usalp->errfile,
640                                                 "usalo_initiator_id: id = %d\n", t);
641                                 }
642                                 return (t);
643                         }
644         }
645
646         return (-1);
647 }
648
649 static int
650 usalo_isatapi(SCSI *usalp)
651 {
652         /* if the new address method is used we know if this is ATAPI */
653
654         return ((sdidevs[usal_scsibus(usalp)][usal_target(usalp)][usal_lun(usalp)].flags & SDI_ATAPI) != 0);
655 }
656
657 static int
658 usalo_reset(SCSI *usalp, int what)
659 {
660         int     f = usalp->fd;
661
662         errno = EINVAL;
663
664 #if defined(SDI_TRESET) || defined(SDI_BRESET)
665         if (what == SCG_RESET_NOP) {
666                 errno = 0;
667                 return (0);
668         }
669
670 #ifdef  SDI_TRESET
671         if (what == SCG_RESET_TGT) {
672                 errno = 0;
673                 if (ioctl(f, SDI_TRESET, 0) >= 0)
674                         return (0);
675         }
676 #endif
677
678 #ifdef  SDI_BRESET
679         if (what == SCG_RESET_BUS) {
680                 errno = 0;
681                 if (ioctl(f, SDI_BRESET, 0) >= 0)
682                         return (0);
683         }
684 #endif
685
686 #endif  /* defined(SDI_TRESET) || defined(SDI_BRESET) */
687
688         return (-1);
689 }
690
691 static int
692 do_usal_cmd(SCSI *usalp, struct usal_cmd *sp)
693 {
694         int                     ret;
695         int                     i;
696         struct sb               scsi_cmd;
697         struct scb              *scbp;
698
699         memset(&scsi_cmd,  0, sizeof (scsi_cmd));
700
701         scsi_cmd.sb_type = ISCB_TYPE;
702         scbp = &scsi_cmd.SCB;
703
704         scbp->sc_cmdpt = (caddr_t) sp->cdb.cmd_cdb;
705         scbp->sc_cmdsz = sp->cdb_len;
706
707         scbp->sc_datapt = sp->addr;
708         scbp->sc_datasz = sp->size;
709
710         if (!(sp->flags & SCG_RECV_DATA) && (sp->size > 0))
711                 scbp->sc_mode = SCB_WRITE;
712         else
713                 scbp->sc_mode = SCB_READ;
714
715         scbp->sc_time = sp->timeout;
716
717         sp->error = SCG_NO_ERROR;
718         errno = 0;
719         for (;;) {
720                 if ((ret = ioctl(usalp->fd, SDI_SEND, &scsi_cmd)) < 0) {
721                         if (errno == EAGAIN) {
722                                 sleep(1);
723                                 errno = 0;
724                                 continue;
725                         }
726                         sp->ux_errno = errno;
727                         if (errno == 0)
728                                 sp->ux_errno = EIO;
729                         sp->error = SCG_RETRYABLE;
730
731 #ifdef  __needed__
732                         if (errno == ENOTTY || errno == EINVAL ||
733                             errno == EACCES) {
734                                 return (-1);
735                         }
736 #endif
737                         return (ret);
738                 }
739                 break;
740         }
741         sp->ux_errno = errno;
742         sp->resid = scbp->sc_resid;
743         memset(&sp->u_scb.Scb, 0, sizeof (sp->u_scb.Scb));
744         sp->u_scb.cmd_scb[0] = scbp->sc_status;
745
746         if (sp->u_scb.cmd_scb[0] & 0x02) {
747                 if (sp->ux_errno == 0)
748                         sp->ux_errno = EIO;
749         }
750
751         switch (scbp->sc_comp_code) {
752
753                 case SDI_ASW     : /* Job completed normally            */
754                 case SDI_LINKF0  : /* Linked command done without flag  */
755                 case SDI_LINKF1  : /* Linked command done with flag     */
756
757                                 sp->error = SCG_NO_ERROR;
758                                 break;
759
760                 case SDI_CKSTAT  : /* Check the status byte             */
761
762                                 sp->error = SCG_NO_ERROR;
763                                 break;
764
765                 case SDI_NOALLOC : /* This block is not allocated       */
766                 case SDI_NOTEQ   : /* Addressed device not present      */
767                 case SDI_OOS     : /* Device is out of service          */
768                 case SDI_NOSELE  : /* The SCSI bus select failed        */
769                 case SDI_SBRESC  : /* SCSI bus reservation conflict     */
770
771                                 sp->error = SCG_FATAL;
772                                 if (sp->ux_errno == 0)
773                                         sp->ux_errno = EIO;
774                                 break;
775
776                 case SDI_QFLUSH  : /* Job was flushed                   */
777                 case SDI_ABORT   : /* Command was aborted               */
778                 case SDI_RESET   : /* Reset was detected on the bus     */
779                 case SDI_CRESET  : /* Reset was caused by this unit     */
780                 case SDI_V2PERR  : /* vtop failed                       */
781                 case SDI_HAERR   : /* Host adapter error                */
782                 case SDI_MEMERR  : /* Memory fault                      */
783                 case SDI_SBUSER  : /* SCSI bus error                    */
784                 case SDI_SCBERR  : /* SCB error                         */
785                 case SDI_MISMAT  : /* parameter mismatch                */
786
787                 case SDI_PROGRES : /* Job in progress                   */
788                 case SDI_UNUSED  : /* Job not in use                    */
789
790                 case SDI_ONEIC   : /* More than one immediate request   */
791                 case SDI_SFBERR  : /* SFB error                         */
792                 case SDI_TCERR   : /* Target protocol error detected    */
793                 default:
794                                 sp->error = SCG_RETRYABLE;
795                                 if (sp->ux_errno == 0)
796                                         sp->ux_errno = EIO;
797                                 break;
798
799                 case SDI_TIME    : /* Job timed out                     */
800                 case SDI_TIME_NOABORT : /* Job timed out, but could not be aborted */
801
802                                 sp->error = SCG_TIMEOUT;
803                                 if (sp->ux_errno == 0)
804                                         sp->ux_errno = EIO;
805                                 break;
806         }
807         return (0);
808 }
809
810
811 static int
812 do_usal_sense(SCSI *usalp, struct usal_cmd *sp)
813 {
814         int             ret;
815         struct usal_cmd s_cmd;
816
817         memset((caddr_t)&s_cmd, 0, sizeof (s_cmd));
818
819         s_cmd.addr      = (caddr_t) sp->u_sense.cmd_sense;
820         s_cmd.size      = sp->sense_len;
821         s_cmd.flags     = SCG_RECV_DATA|SCG_DISRE_ENA;
822         s_cmd.cdb_len   = SC_G0_CDBLEN;
823         s_cmd.sense_len = CCS_SENSE_LEN;
824
825         s_cmd.cdb.g0_cdb.cmd   = SC_REQUEST_SENSE;
826         s_cmd.cdb.g0_cdb.lun   = sp->cdb.g0_cdb.lun;
827         s_cmd.cdb.g0_cdb.count = sp->sense_len;
828
829         ret = do_usal_cmd(usalp, &s_cmd);
830
831         if (ret < 0)
832                 return (ret);
833
834         sp->sense_count = sp->sense_len - s_cmd.resid;
835         return (ret);
836 }
837
838 static int
839 usalo_send(SCSI *usalp)
840 {
841         struct usal_cmd *sp = usalp->scmd;
842         int     ret;
843
844         if (usalp->fd < 0) {
845                 sp->error = SCG_FATAL;
846                 return (0);
847         }
848
849         ret = do_usal_cmd(usalp, sp);
850         if (ret < 0)
851                 return (ret);
852
853         if (sp->u_scb.cmd_scb[0] & S_CKCON)
854                 ret = do_usal_sense(usalp, sp);
855
856         return (ret);
857 }
858
859 #define sense   u_sense.Sense
860 #undef  SC_PARITY
861 #define SC_PARITY       0x09
862 #define scb             u_scb.Scb
863
864 /*--------------------------------------------------------------------------*/
865 #include <unixstd.h>
866 #include <waitdefs.h>
867 /*
868  * Simplified version of popen()
869  * This version of popen() is not usable more than once at a time.
870  * Needed because /etc/scsi/pdiconfig will not work if euid != uid
871  */
872 static pid_t    po_pid;
873
874 static FILE *
875 xpopen(char *cmd, char *type)
876 {
877         FILE    *ret;
878         FILE    *pp[2];
879
880         if (po_pid != 0)
881                 return ((FILE *)NULL);
882
883         if (*type != 'r')
884                 return ((FILE *)NULL);
885
886         if (fpipe(pp) == 0)
887                 return ((FILE *)NULL);
888
889
890         if ((po_pid = fork()) == 0) {
891                 setuid(0);
892
893                 fclose(pp[0]);
894                 (void) rols_fexecl("/bin/sh", stdin, pp[1], stderr,
895                                         "sh", "-c", cmd, (char *)0);
896                 _exit(1);
897         }
898         fclose(pp[1]);
899
900         if (po_pid == (pid_t)-1) {
901                 fclose(pp[0]);
902                 return ((FILE *)NULL);
903         }
904         return (pp[0]);
905 }
906
907 static int
908 xpclose(FILE *f)
909 {
910         int     ret = 0;
911
912         if (po_pid == 0)
913                 return (-1);
914
915         fclose(f);
916
917         if (waitpid(po_pid, &ret, 0) < 0)
918                 ret = -1;
919
920         po_pid = 0;
921         return (ret);
922 }