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