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