1 /* @(#)scsi-bsd-os.c	1.29 06/11/26 Copyright 1997 J. Schilling */
2 #ifndef lint
3 static	char __sccsid[] =
4 	"@(#)scsi-bsd-os.c	1.29 06/11/26 Copyright 1997 J. Schilling";
5 #endif
6 /*
7  *	Interface for the BSD/OS user-land raw SCSI implementation.
8  *
9  *	This is a hack, that tries to emulate the functionality
10  *	of the scg driver.
11  *
12  *	Warning: you may change this source, but if you do that
13  *	you need to change the _scg_version and _scg_auth* string below.
14  *	You may not return "schily" for an SCG_AUTHOR request anymore.
15  *	Choose your name instead of "schily" and make clear that the version
16  *	string is related to a modified source.
17  *
18  *	Copyright (c) 1997 J. Schilling
19  */
20 /*
21  * The contents of this file are subject to the terms of the
22  * Common Development and Distribution License, Version 1.0 only
23  * (the "License").  You may not use this file except in compliance
24  * with the License.
25  *
26  * See the file CDDL.Schily.txt in this distribution for details.
27  * A copy of the CDDL is also available via the Internet at
28  * http://www.opensource.org/licenses/cddl1.txt
29  *
30  * The following exceptions apply:
31  * CDDL �3.6 needs to be replaced by: "You may create a Larger Work by
32  * combining Covered Software with other code if all other code is governed by
33  * the terms of a license that is OSI approved (see www.opensource.org) and
34  * you may distribute the Larger Work as a single product. In such a case,
35  * You must make sure the requirements of this License are fulfilled for
36  * the Covered Software."
37  *
38  * When distributing Covered Code, include this CDDL HEADER in each
39  * file and include the License file CDDL.Schily.txt from this distribution.
40  */
41 
42 #undef	sense
43 
44 #define	scsi_sense	bsdi_scsi_sense
45 #define	scsi_inquiry	bsdi_scsi_inquiry
46 
47 /*
48  * Must use -I/sys...
49  * The next two files are in /sys/dev/scsi
50  */
51 #include <dev/scsi/scsi.h>
52 #include <dev/scsi/scsi_ioctl.h>
53 
54 /*
55  *	Warning: you may change this source, but if you do that
56  *	you need to change the _scg_version and _scg_auth* string below.
57  *	You may not return "schily" for an SCG_AUTHOR request anymore.
58  *	Choose your name instead of "schily" and make clear that the version
59  *	string is related to a modified source.
60  */
61 LOCAL	char	_scg_trans_version[] = "scsi-bsd-os.c-1.29";	/* The version for this transport*/
62 
63 #define	MAX_SCG		16	/* Max # of SCSI controllers */
64 #define	MAX_TGT		16
65 #define	MAX_LUN		8
66 
67 struct scg_local {
68 	short	scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
69 };
70 #define	scglocal(p)	((struct scg_local *)((p)->local))
71 
72 #include <machine/param.h>
73 
74 #define	MAX_DMA_BSDI	MAXPHYS		/* More makes problems */
75 
76 
77 LOCAL	BOOL	scg_setup	__PR((SCSI *scgp, int f, int busno, int tgt, int tlun));
78 
79 /*
80  * Return version information for the low level SCSI transport code.
81  * This has been introduced to make it easier to trace down problems
82  * in applications.
83  */
84 LOCAL char *
scgo_version(scgp,what)85 scgo_version(scgp, what)
86 	SCSI	*scgp;
87 	int	what;
88 {
89 	if (scgp != (SCSI *)0) {
90 		switch (what) {
91 
92 		case SCG_VERSION:
93 			return (_scg_trans_version);
94 		/*
95 		 * If you changed this source, you are not allowed to
96 		 * return "schily" for the SCG_AUTHOR request.
97 		 */
98 		case SCG_AUTHOR:
99 			return (_scg_auth_schily);
100 		case SCG_SCCS_ID:
101 			return (__sccsid);
102 		}
103 	}
104 	return ((char *)0);
105 }
106 
107 LOCAL int
scgo_help(scgp,f)108 scgo_help(scgp, f)
109 	SCSI	*scgp;
110 	FILE	*f;
111 {
112 	__scg_help(f, "SCSIRAWCDB", "Generic SCSI for devices known by BSDi",
113 		"", "devname:@,lun", "/dev/rsr0a:@,0", FALSE, TRUE);
114 	return (0);
115 }
116 
117 LOCAL int
scgo_open(scgp,device)118 scgo_open(scgp, device)
119 	SCSI	*scgp;
120 	char	*device;
121 {
122 		int	busno	= scg_scsibus(scgp);
123 		int	tgt	= scg_target(scgp);
124 		int	tlun	= scg_lun(scgp);
125 	register int	f;
126 	register int	b;
127 	register int	t;
128 	register int	l;
129 	register int	nopen = 0;
130 	char		devname[64];
131 
132 	if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
133 		errno = EINVAL;
134 		if (scgp->errstr)
135 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
136 				"Illegal value for busno, target or lun '%d,%d,%d'",
137 				busno, tgt, tlun);
138 		return (-1);
139 	}
140 
141 	if (scgp->local == NULL) {
142 		scgp->local = malloc(sizeof (struct scg_local));
143 		if (scgp->local == NULL)
144 			return (0);
145 
146 		for (b = 0; b < MAX_SCG; b++) {
147 			for (t = 0; t < MAX_TGT; t++) {
148 				for (l = 0; l < MAX_LUN; l++)
149 					scglocal(scgp)->scgfiles[b][t][l] = (short)-1;
150 			}
151 		}
152 	}
153 
154 	if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2))
155 		goto openbydev;
156 
157 	if (busno >= 0 && tgt >= 0 && tlun >= 0) {
158 
159 		js_snprintf(devname, sizeof (devname),
160 					"/dev/su%d-%d-%d", busno, tgt, tlun);
161 		f = open(devname, O_RDWR|O_NONBLOCK);
162 		if (f < 0) {
163 			goto openbydev;
164 		}
165 		scglocal(scgp)->scgfiles[busno][tgt][tlun] = f;
166 		return (1);
167 
168 	} else for (b = 0; b < MAX_SCG; b++) {
169 		for (t = 0; t < MAX_TGT; t++) {
170 			for (l = 0; l < MAX_LUN; l++) {
171 				js_snprintf(devname, sizeof (devname),
172 						"/dev/su%d-%d-%d", b, t, l);
173 				f = open(devname, O_RDWR|O_NONBLOCK);
174 /*				error("open (%s) = %d\n", devname, f);*/
175 
176 				if (f < 0) {
177 					if (errno != ENOENT &&
178 					    errno != ENXIO &&
179 					    errno != ENODEV) {
180 						if (scgp->errstr)
181 							js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
182 								"Cannot open '%s'",
183 								devname);
184 						return (0);
185 					}
186 				} else {
187 					if (scg_setup(scgp, f, b, t, l))
188 						nopen++;
189 				}
190 			}
191 		}
192 	}
193 	/*
194 	 * Could not open /dev/su-* or got dev=devname:b,l,l / dev=devname:@,l
195 	 * We do the apropriate tests and try our best.
196 	 */
197 openbydev:
198 	if (nopen == 0) {
199 		if (device == NULL || device[0] == '\0')
200 			return (0);
201 		f = open(device, O_RDWR|O_NONBLOCK);
202 		if (f < 0) {
203 			if (scgp->errstr)
204 				js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
205 					"Cannot open '%s'",
206 					device);
207 			return (0);
208 		}
209 		if (tlun == -2) {	/* If 'lun' is not known, we reject */
210 			close(f);
211 			errno = EINVAL;
212 			return (0);
213 		}
214 		busno = 0;		/* use fake number, we cannot get it */
215 		tgt   = 0;		/* use fake number, we cannot get it */
216 		scg_settarget(scgp, busno, tgt, tlun);
217 		/* 'lun' has been specified on command line */
218 		if (scg_setup(scgp, f, busno, tgt, tlun))
219 			nopen++;
220 	}
221 	return (nopen);
222 }
223 
224 LOCAL int
scgo_close(scgp)225 scgo_close(scgp)
226 	SCSI	*scgp;
227 {
228 	register int	f;
229 	register int	b;
230 	register int	t;
231 	register int	l;
232 
233 	if (scgp->local == NULL)
234 		return (-1);
235 
236 	for (b = 0; b < MAX_SCG; b++) {
237 		for (t = 0; t < MAX_TGT; t++) {
238 			for (l = 0; l < MAX_LUN; l++) {
239 				f = scglocal(scgp)->scgfiles[b][t][l];
240 				if (f >= 0)
241 					close(f);
242 				scglocal(scgp)->scgfiles[b][t][l] = (short)-1;
243 			}
244 		}
245 	}
246 	return (0);
247 }
248 
249 LOCAL BOOL
scg_setup(scgp,f,busno,tgt,tlun)250 scg_setup(scgp, f, busno, tgt, tlun)
251 	SCSI	*scgp;
252 	int	f;
253 	int	busno;
254 	int	tgt;
255 	int	tlun;
256 {
257 	int	Bus;
258 	int	Target;
259 	int	Lun;
260 	BOOL	onetarget = FALSE;
261 
262 	if (scg_scsibus(scgp) >= 0 && scg_target(scgp) >= 0 && scg_lun(scgp) >= 0)
263 		onetarget = TRUE;
264 
265 	/*
266 	 * Unfortunately there is no way to get the right values from kernel.
267 	 */
268 	Bus	= busno;
269 	Target	= tgt;
270 	Lun	= tlun;
271 
272 	if (scgp->debug > 0) {
273 		js_fprintf((FILE *)scgp->errfile,
274 			"Bus: %d Target: %d Lun: %d\n", Bus, Target, Lun);
275 	}
276 
277 	if (Bus >= MAX_SCG || Target >= MAX_TGT || Lun >= MAX_LUN) {
278 		close(f);
279 		return (FALSE);
280 	}
281 
282 	if (scglocal(scgp)->scgfiles[Bus][Target][Lun] == (short)-1)
283 		scglocal(scgp)->scgfiles[Bus][Target][Lun] = (short)f;
284 
285 	if (onetarget) {
286 		if (Bus == busno && Target == tgt && Lun == tlun) {
287 			return (TRUE);
288 		} else {
289 			scglocal(scgp)->scgfiles[Bus][Target][Lun] = (short)-1;
290 			close(f);
291 		}
292 	}
293 	return (FALSE);
294 }
295 
296 LOCAL long
scgo_maxdma(scgp,amt)297 scgo_maxdma(scgp, amt)
298 	SCSI	*scgp;
299 	long	amt;
300 {
301 	long maxdma = MAX_DMA_BSDI;
302 
303 	return (maxdma);
304 }
305 
306 LOCAL void *
scgo_getbuf(scgp,amt)307 scgo_getbuf(scgp, amt)
308 	SCSI	*scgp;
309 	long	amt;
310 {
311 	if (scgp->debug > 0) {
312 		js_fprintf((FILE *)scgp->errfile,
313 			"scgo_getbuf: %ld bytes\n", amt);
314 	}
315 	scgp->bufbase = malloc((size_t)(amt));
316 	return (scgp->bufbase);
317 }
318 
319 LOCAL void
scgo_freebuf(scgp)320 scgo_freebuf(scgp)
321 	SCSI	*scgp;
322 {
323 	if (scgp->bufbase)
324 		free(scgp->bufbase);
325 	scgp->bufbase = NULL;
326 }
327 
328 LOCAL int
scgo_numbus(scgp)329 scgo_numbus(scgp)
330 	SCSI	*scgp;
331 {
332 	return (MAX_SCG);
333 }
334 
335 LOCAL BOOL
scgo_havebus(scgp,busno)336 scgo_havebus(scgp, busno)
337 	SCSI	*scgp;
338 	int	busno;
339 {
340 	register int	t;
341 	register int	l;
342 
343 	if (busno < 0 || busno >= MAX_SCG)
344 		return (FALSE);
345 
346 	if (scgp->local == NULL)
347 		return (FALSE);
348 
349 	for (t = 0; t < MAX_TGT; t++) {
350 		for (l = 0; l < MAX_LUN; l++)
351 			if (scglocal(scgp)->scgfiles[busno][t][l] >= 0)
352 				return (TRUE);
353 	}
354 	return (FALSE);
355 }
356 
357 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)358 scgo_fileno(scgp, busno, tgt, tlun)
359 	SCSI	*scgp;
360 	int	busno;
361 	int	tgt;
362 	int	tlun;
363 {
364 	if (busno < 0 || busno >= MAX_SCG ||
365 	    tgt < 0 || tgt >= MAX_TGT ||
366 	    tlun < 0 || tlun >= MAX_LUN)
367 		return (-1);
368 
369 	if (scgp->local == NULL)
370 		return (-1);
371 
372 	return ((int)scglocal(scgp)->scgfiles[busno][tgt][tlun]);
373 }
374 
375 LOCAL int
scgo_initiator_id(scgp)376 scgo_initiator_id(scgp)
377 	SCSI	*scgp;
378 {
379 	return (-1);
380 }
381 
382 LOCAL int
scgo_isatapi(scgp)383 scgo_isatapi(scgp)
384 	SCSI	*scgp;
385 {
386 	return (FALSE);
387 }
388 
389 LOCAL int
scgo_reset(scgp,what)390 scgo_reset(scgp, what)
391 	SCSI	*scgp;
392 	int	what;
393 {
394 	/*
395 	 * Cannot reset on BSD/OS
396 	 */
397 	errno = EINVAL;
398 	return (-1);
399 }
400 
401 LOCAL int
scgo_send(scgp)402 scgo_send(scgp)
403 	SCSI		*scgp;
404 {
405 	struct scg_cmd	*sp = scgp->scmd;
406 	scsi_user_cdb_t	suc;
407 	int		ret = 0;
408 
409 /*	js_fprintf((FILE *)scgp->errfile, "f: %d\n", f);*/
410 	if (scgp->fd < 0) {
411 		sp->error = SCG_FATAL;
412 		return (0);
413 	}
414 
415 	/* Zero the structure... */
416 	fillbytes(&suc, sizeof (suc), '\0');
417 
418 	/* Read or write? */
419 	if (sp->flags & SCG_RECV_DATA) {
420 		suc.suc_flags |= SUC_READ;
421 	} else if (sp->size > 0) {
422 		suc.suc_flags |= SUC_WRITE;
423 	}
424 
425 	suc.suc_timeout = sp->timeout;
426 
427 	suc.suc_cdblen = sp->cdb_len;
428 	movebytes(sp->cdb.cmd_cdb, suc.suc_cdb, suc.suc_cdblen);
429 
430 	suc.suc_datalen = sp->size;
431 	suc.suc_data = sp->addr;
432 
433 	if (ioctl(scgp->fd, SCSIRAWCDB, &suc) < 0) {
434 		ret  = -1;
435 		sp->ux_errno = geterrno();
436 		if (sp->ux_errno != ENOTTY)
437 			ret = 0;
438 	} else {
439 		sp->ux_errno = 0;
440 		if (suc.suc_sus.sus_status != STS_GOOD)
441 			sp->ux_errno = EIO;
442 	}
443 	fillbytes(&sp->scb, sizeof (sp->scb), '\0');
444 	fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0');
445 #if 0
446 	/*
447 	 * Unfortunalety, BSD/OS has no idea of DMA residual count.
448 	 */
449 	sp->resid = req.datalen - req.datalen_used;
450 	sp->sense_count = req.senselen_used;
451 #else
452 	sp->resid = 0;
453 	sp->sense_count = sizeof (suc.suc_sus.sus_sense);
454 #endif
455 	if (sp->sense_count > SCG_MAX_SENSE)
456 		sp->sense_count = SCG_MAX_SENSE;
457 	movebytes(suc.suc_sus.sus_sense, sp->u_sense.cmd_sense, sp->sense_count);
458 	sp->u_scb.cmd_scb[0] = suc.suc_sus.sus_status;
459 
460 	switch (suc.suc_sus.sus_status) {
461 
462 	case STS_GOOD:
463 				sp->error = SCG_NO_ERROR;	break;
464 	case STS_CMD_TERMINATED:sp->error = SCG_TIMEOUT;	break;
465 	case STS_BUSY:		sp->error = SCG_RETRYABLE;	break;
466 	case STS_CHECKCOND:	sp->error = SCG_RETRYABLE;	break;
467 	case STS_QUEUE_FULL:	sp->error = SCG_RETRYABLE;	break;
468 	default:		sp->error = SCG_FATAL;		break;
469 	}
470 
471 	return (ret);
472 }
473 
474 #define	sense	u_sense.Sense
475 
476 #undef scsi_sense
477 #undef scsi_inquiry
478