1 /* @(#)scsi-next.c	1.33 06/11/26 Copyright 1997 J. Schilling */
2 #ifndef lint
3 static	char __sccsid[] =
4 	"@(#)scsi-next.c	1.33 06/11/26 Copyright 1997 J. Schilling";
5 #endif
6 /*
7  *	Interface for the NeXT Step generic 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 #include <bsd/dev/scsireg.h>
43 
44 /*
45  *	Warning: you may change this source, but if you do that
46  *	you need to change the _scg_version and _scg_auth* string below.
47  *	You may not return "schily" for an SCG_AUTHOR request anymore.
48  *	Choose your name instead of "schily" and make clear that the version
49  *	string is related to a modified source.
50  */
51 LOCAL	char	_scg_trans_version[] = "scsi-next.c-1.33";	/* The version for this transport*/
52 
53 #define	MAX_SCG		16	/* Max # of SCSI controllers */
54 #define	MAX_TGT		16
55 #define	MAX_LUN		8
56 
57 struct scg_local {
58 	short	scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
59 	int	scgfile;
60 	int	max_scsibus;
61 	int	cur_scsibus;
62 	int	cur_target;
63 	int	cur_lun;
64 };
65 #define	scglocal(p)	((struct scg_local *)((p)->local))
66 
67 /*#define	MAX_DMA_NEXT	(32*1024)*/
68 #define	MAX_DMA_NEXT	(64*1024)	/* Check if this is not too big */
69 
70 
71 LOCAL	BOOL	scg_setup	__PR((SCSI *scgp, int busno, int tgt, int tlun,
72 								BOOL ex));
73 
74 /*
75  * Return version information for the low level SCSI transport code.
76  * This has been introduced to make it easier to trace down problems
77  * in applications.
78  */
79 LOCAL char *
scgo_version(scgp,what)80 scgo_version(scgp, what)
81 	SCSI	*scgp;
82 	int	what;
83 {
84 	if (scgp != (SCSI *)0) {
85 		switch (what) {
86 
87 		case SCG_VERSION:
88 			return (_scg_trans_version);
89 		/*
90 		 * If you changed this source, you are not allowed to
91 		 * return "schily" for the SCG_AUTHOR request.
92 		 */
93 		case SCG_AUTHOR:
94 			return (_scg_auth_schily);
95 		case SCG_SCCS_ID:
96 			return (__sccsid);
97 		}
98 	}
99 	return ((char *)0);
100 }
101 
102 LOCAL int
scgo_help(scgp,f)103 scgo_help(scgp, f)
104 	SCSI	*scgp;
105 	FILE	*f;
106 {
107 	__scg_help(f, "SGIOCREQ", "Generic SCSI",
108 		"", "bus,target,lun", "1,2,0", TRUE, FALSE);
109 	return (0);
110 }
111 
112 LOCAL int
scgo_open(scgp,device)113 scgo_open(scgp, device)
114 	SCSI	*scgp;
115 	char	*device;
116 {
117 		int	busno	= scg_scsibus(scgp);
118 		int	tgt	= scg_target(scgp);
119 		int	tlun	= scg_lun(scgp);
120 	register int	f;
121 	register int	i;
122 	char		devname[64];
123 
124 	if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
125 		errno = EINVAL;
126 		if (scgp->errstr)
127 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
128 				"Illegal value for busno, target or lun '%d,%d,%d'",
129 				busno, tgt, tlun);
130 		return (-1);
131 	}
132 
133 	if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
134 		errno = EINVAL;
135 		if (scgp->errstr)
136 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
137 				"Open by 'devname' not supported on this OS");
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 		scglocal(scgp)->scgfile		= -1;
147 		scglocal(scgp)->max_scsibus	= -1;
148 		scglocal(scgp)->cur_scsibus	= -1;
149 		scglocal(scgp)->cur_target	= -1;
150 		scglocal(scgp)->cur_lun		= -1;
151 	}
152 
153 	for (i = 0; i < 4; i++) {
154 		js_snprintf(devname, sizeof (devname), "/dev/sg%d", i);
155 		f = open(devname, O_RDWR);
156 		if (scgp->debug > 0)
157 			errmsg("open(devname: '%s') : %d\n", devname, f);
158 		if (f < 0)
159 			continue;
160 		scglocal(scgp)->scgfile = f;
161 		break;
162 
163 	}
164 	if (f >= 0) {
165 		if (scglocal(scgp)->max_scsibus < 0) {
166 			for (i = 0; i < MAX_SCG; i++) {
167 				if (!SCGO_HAVEBUS(scgp, i))
168 					break;
169 			}
170 			scglocal(scgp)->max_scsibus = i;
171 		}
172 		if (scgp->debug > 0) {
173 			js_fprintf((FILE *)scgp->errfile,
174 				"maxbus: %d\n", scglocal(scgp)->max_scsibus);
175 		}
176 		if (scglocal(scgp)->max_scsibus <= 0) {
177 			scglocal(scgp)->max_scsibus = 1;
178 			scglocal(scgp)->cur_scsibus = 0;
179 		}
180 
181 		ioctl(f, SGIOCENAS);
182 		if (busno > 0 && tgt > 0 && tlun > 0)
183 			scg_setup(scgp, busno, tgt, tlun, TRUE);
184 		return (1);
185 	}
186 	if (scgp->errstr)
187 		js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
188 			"Cannot open '/dev/sg*'");
189 	return (0);
190 }
191 
192 LOCAL int
scgo_close(scgp)193 scgo_close(scgp)
194 	SCSI	*scgp;
195 {
196 	if (scgp->local == NULL)
197 		return (-1);
198 
199 	if (scglocal(scgp)->scgfile >= 0)
200 		close(scglocal(scgp)->scgfile);
201 	scglocal(scgp)->scgfile = -1;
202 	return (0);
203 }
204 
205 LOCAL BOOL
scg_setup(scgp,busno,tgt,tlun,ex)206 scg_setup(scgp, busno, tgt, tlun, ex)
207 	SCSI	*scgp;
208 	int	busno;
209 	int	tgt;
210 	int	tlun;
211 	BOOL	ex;
212 {
213 	scsi_adr_t sadr;
214 
215 	sadr.sa_target = tgt;
216 	sadr.sa_lun = tlun;
217 
218 	if (scgp->debug > 0) {
219 		js_fprintf((FILE *)scgp->errfile,
220 			"scg_setup curbus %d -> %d\n", scglocal(scgp)->cur_scsibus, busno);
221 	}
222 
223 	if (scgp->debug > 0 && ((scglocal(scgp)->cur_scsibus < 0 || scglocal(scgp)->cur_scsibus != busno)))
224 		js_fprintf((FILE *)scgp->errfile, "setting SCSI bus to: %d\n", busno);
225 	if ((scglocal(scgp)->cur_scsibus < 0 || scglocal(scgp)->cur_scsibus != busno) &&
226 				ioctl(scglocal(scgp)->scgfile, SGIOCCNTR, &busno) < 0) {
227 
228 		scglocal(scgp)->cur_scsibus = -1;	/* Driver is in undefined state */
229 		if (ex)
230 /*			comerr("Cannot set SCSI bus\n");*/
231 			errmsg("Cannot set SCSI bus\n");
232 		return (FALSE);
233 	}
234 	scglocal(scgp)->cur_scsibus	= busno;
235 
236 	if (scgp->debug > 0) {
237 		js_fprintf((FILE *)scgp->errfile,
238 			"setting target/lun to: %d/%d\n", tgt, tlun);
239 	}
240 	if (ioctl(scglocal(scgp)->scgfile, SGIOCSTL, &sadr) < 0) {
241 		if (ex)
242 			comerr("Cannot set SCSI address\n");
243 		return (FALSE);
244 	}
245 	scglocal(scgp)->cur_scsibus	= busno;
246 	scglocal(scgp)->cur_target	= tgt;
247 	scglocal(scgp)->cur_lun		= tlun;
248 	return (TRUE);
249 }
250 
251 LOCAL long
scgo_maxdma(scgp,amt)252 scgo_maxdma(scgp, amt)
253 	SCSI	*scgp;
254 	long	amt;
255 {
256 	long maxdma = MAX_DMA_NEXT;
257 #ifdef	SGIOCMAXDMA
258 	int  m;
259 
260 	if (ioctl(scglocal(scgp)->scgfile, SGIOCMAXDMA, &m) >= 0) {
261 		maxdma = m;
262 		if (scgp->debug > 0) {
263 			js_fprintf((FILE *)scgp->errfile,
264 				"maxdma: %d\n", maxdma);
265 		}
266 	}
267 #endif
268 	return (maxdma);
269 }
270 #ifdef	XXX
271 #define	SGIOCENAS	_IO('s', 2)			/* enable autosense */
272 #define	SGIOCDAS	_IO('s', 3)			/* disable autosense */
273 #define	SGIOCRST	_IO('s', 4)			/* reset SCSI bus */
274 #define	SGIOCCNTR	_IOW('s', 6, int)		/* select controller */
275 #define	SGIOCGAS	_IOR('s', 7, int)		/* get autosense */
276 #define	SGIOCMAXDMA	_IOR('s', 8, int)		/* max DMA size */
277 #define	SGIOCNUMTARGS	_IOR('s', 9, int)		/* # of targets/bus */
278 #endif
279 
280 LOCAL void *
scgo_getbuf(scgp,amt)281 scgo_getbuf(scgp, amt)
282 	SCSI	*scgp;
283 	long	amt;
284 {
285 	if (scgp->debug > 0) {
286 		js_fprintf((FILE *)scgp->errfile,
287 			"scgo_getbuf: %ld bytes\n", amt);
288 	}
289 	scgp->bufbase = valloc((size_t)(amt));
290 	return (scgp->bufbase);
291 }
292 
293 LOCAL void
scgo_freebuf(scgp)294 scgo_freebuf(scgp)
295 	SCSI	*scgp;
296 {
297 	if (scgp->bufbase)
298 		free(scgp->bufbase);
299 	scgp->bufbase = NULL;
300 }
301 
302 LOCAL int
scgo_numbus(scgp)303 scgo_numbus(scgp)
304 	SCSI	*scgp;
305 {
306 	return (MAX_SCG);
307 }
308 
309 LOCAL BOOL
scgo_havebus(scgp,busno)310 scgo_havebus(scgp, busno)
311 	SCSI	*scgp;
312 	int	busno;
313 {
314 	if (busno < 0 || busno >= MAX_SCG)
315 		return (FALSE);
316 
317 	if (scgp->local == NULL)
318 		return (FALSE);
319 
320 	if (scglocal(scgp)->max_scsibus > 0 && busno >= scglocal(scgp)->max_scsibus)
321 		return (FALSE);
322 
323 	return (scg_setup(scgp, busno, 0, 0, FALSE));
324 }
325 
326 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)327 scgo_fileno(scgp, busno, tgt, tlun)
328 	SCSI	*scgp;
329 	int	busno;
330 	int	tgt;
331 	int	tlun;
332 {
333 	if (busno < 0 || busno >= MAX_SCG ||
334 	    tgt < 0 || tgt >= MAX_TGT ||
335 	    tlun < 0 || tlun >= MAX_LUN)
336 		return (-1);
337 	if (scglocal(scgp)->max_scsibus > 0 && busno >= scglocal(scgp)->max_scsibus)
338 		return (-1);
339 
340 	if (scgp->local == NULL)
341 		return (-1);
342 
343 	if ((busno != scglocal(scgp)->cur_scsibus) || (tgt != scglocal(scgp)->cur_target) || (tlun != scglocal(scgp)->cur_lun)) {
344 		if (!scg_setup(scgp, busno, tgt, tlun, FALSE))
345 			return (-1);
346 	}
347 	return (scglocal(scgp)->scgfile);
348 }
349 
350 LOCAL int
scgo_initiator_id(scgp)351 scgo_initiator_id(scgp)
352 	SCSI	*scgp;
353 {
354 	return (-1);
355 }
356 
357 LOCAL int
scgo_isatapi(scgp)358 scgo_isatapi(scgp)
359 	SCSI	*scgp;
360 
361 {
362 	return (FALSE);
363 }
364 
365 LOCAL int
scgo_reset(scgp,what)366 scgo_reset(scgp, what)
367 	SCSI	*scgp;
368 	int	what;
369 {
370 	if (what == SCG_RESET_NOP)
371 		return (0);
372 	if (what != SCG_RESET_BUS) {
373 		errno = EINVAL;
374 		return (-1);
375 	}
376 	return (ioctl(scgp->fd, SGIOCRST, 0));
377 }
378 
379 LOCAL int
scgo_send(scgp)380 scgo_send(scgp)
381 	SCSI		*scgp;
382 {
383 	struct scg_cmd	*sp = scgp->scmd;
384 	struct scsi_req	req;
385 	register long	*lp1;
386 	register long	*lp2;
387 	int		ret = 0;
388 
389 	if (scgp->fd < 0 || (sp->cdb_len > sizeof (req.sr_cdb))) {
390 		sp->error = SCG_FATAL;
391 		sp->ux_errno = EIO;
392 		return (0);
393 	}
394 	fillbytes(&req, sizeof (req), '\0');
395 	movebytes(sp->cdb.cmd_cdb, &req.sr_cdb, sp->cdb_len);
396 	if (sp->size) {
397 		req.sr_dma_dir = SR_DMA_WR;
398 		if (sp->flags & SCG_RECV_DATA)
399 			req.sr_dma_dir = SR_DMA_RD;
400 	}
401 	req.sr_addr = sp->addr;
402 	req.sr_dma_max = sp->size;
403 	req.sr_ioto = sp->timeout;
404 	if (ioctl(scgp->fd, SGIOCREQ, (void *)&req) < 0) {
405 		ret  = -1;
406 		sp->ux_errno = geterrno();
407 		if (sp->ux_errno != ENOTTY)
408 			ret = 0;
409 	} else {
410 		sp->ux_errno = 0;
411 	}
412 	if (scgp->debug > 0) {
413 		js_fprintf((FILE *)scgp->errfile, "dma_dir:     %X\n", req.sr_dma_dir);
414 		js_fprintf((FILE *)scgp->errfile, "dma_addr:    %X\n", req.sr_addr);
415 		js_fprintf((FILE *)scgp->errfile, "io_time:     %d\n", req.sr_ioto);
416 		js_fprintf((FILE *)scgp->errfile, "io_status:   %d\n", req.sr_io_status);
417 		js_fprintf((FILE *)scgp->errfile, "scsi_status: %X\n", req.sr_scsi_status);
418 		js_fprintf((FILE *)scgp->errfile, "dma_xfer:    %d\n", req.sr_dma_xfr);
419 	}
420 	sp->u_scb.cmd_scb[0] = req.sr_scsi_status;
421 	sp->sense_count = sizeof (esense_reply_t);
422 	if (sp->sense_count > sp->sense_len)
423 		sp->sense_count = sp->sense_len;
424 	if (sp->sense_count > SCG_MAX_SENSE)
425 		sp->sense_count = SCG_MAX_SENSE;
426 	if (sp->sense_count < 0)
427 		sp->sense_count = 0;
428 	movebytes(&req.sr_esense, sp->u_sense.cmd_sense, sp->sense_count);
429 	sp->resid = sp->size - req.sr_dma_xfr;
430 
431 	switch (req.sr_io_status) {
432 
433 	case SR_IOST_GOOD:	sp->error = SCG_NO_ERROR;	break;
434 
435 	case SR_IOST_CHKSNV:	sp->sense_count = 0;
436 	case SR_IOST_CHKSV:	sp->error = SCG_RETRYABLE;
437 				break;
438 
439 	case SR_IOST_SELTO:
440 	case SR_IOST_DMAOR:
441 				sp->error = SCG_FATAL;		break;
442 
443 	case SR_IOST_IOTO:	sp->error = SCG_TIMEOUT;	break;
444 
445 	case SR_IOST_PERM:
446 	case SR_IOST_NOPEN:
447 				sp->error = SCG_FATAL;
448 				ret = (-1);
449 				break;
450 
451 	default:		sp->error = SCG_RETRYABLE;	break;
452 
453 	}
454 	return (ret);
455 }
456