1 /* @(#)scsi-beos.c	1.29 09/06/30 Copyright 1998-2009 J. Schilling */
2 #ifndef lint
3 static	char __sccsid[] =
4 	"@(#)scsi-beos.c	1.29 09/06/30 Copyright 1998-2009 J. Schilling";
5 #endif
6 /*
7  *	Interface for the BeOS user-land raw SCSI implementation.
8  *
9  *	This is a hack, that tries to emulate the functionality
10  *	of the scg driver.
11  *
12  *	First version done by swetland@be.com
13  *
14  *	Warning: you may change this source, but if you do that
15  *	you need to change the _scg_version and _scg_auth* string below.
16  *	You may not return "schily" for an SCG_AUTHOR request anymore.
17  *	Choose your name instead of "schily" and make clear that the version
18  *	string is related to a modified source.
19  *
20  *	Copyright (c) 1998-2009 J. Schilling
21  */
22 /*
23  * The contents of this file are subject to the terms of the
24  * Common Development and Distribution License, Version 1.0 only
25  * (the "License").  You may not use this file except in compliance
26  * with the License.
27  *
28  * See the file CDDL.Schily.txt in this distribution for details.
29  * A copy of the CDDL is also available via the Internet at
30  * http://www.opensource.org/licenses/cddl1.txt
31  *
32  * The following exceptions apply:
33  * CDDL �3.6 needs to be replaced by: "You may create a Larger Work by
34  * combining Covered Software with other code if all other code is governed by
35  * the terms of a license that is OSI approved (see www.opensource.org) and
36  * you may distribute the Larger Work as a single product. In such a case,
37  * You must make sure the requirements of this License are fulfilled for
38  * the Covered Software."
39  *
40  * When distributing Covered Code, include this CDDL HEADER in each
41  * file and include the License file CDDL.Schily.txt from this distribution.
42  */
43 
44 
45 /*
46  *	Warning: you may change this source, but if you do that
47  *	you need to change the _scg_version and _scg_auth* string below.
48  *	You may not return "schily" for an SCG_AUTHOR request anymore.
49  *	Choose your name instead of "schily" and make clear that the version
50  *	string is related to a modified source.
51  */
52 LOCAL	char	_scg_trans_version[] = "scsi-beos.c-1.29";	/* The version for this transport*/
53 
54 /*
55  * There are also defines for:
56  *	B_BEOS_VERSION_4
57  *	B_BEOS_VERSION_4_5
58  *
59  * in BeOS 5
60  */
61 #ifdef	B_BEOS_VERSION_5
62 #define	NEW_BEOS
63 #endif
64 #ifdef	__HAIKU__
65 #define	NEW_BEOS
66 #endif
67 
68 #ifndef	NEW_BEOS
69 /*
70  * New BeOS seems to include <be/kernel/OS.h> from device/scsi.h
71  */
72 
73 /* nasty hack to avoid broken def of bool in SupportDefs.h */
74 #define	_SUPPORT_DEFS_H
75 
76 #ifndef _SYS_TYPES_H
77 typedef unsigned long			ulong;
78 typedef unsigned int			uint;
79 typedef unsigned short			ushort;
80 #endif	/* _SYS_TYPES_H */
81 
82 #include <BeBuild.h>
83 #include <schily/types.h>
84 #include <Errors.h>
85 
86 
87 /*-------------------------------------------------------------*/
88 /*----- Shorthand type formats --------------------------------*/
89 
90 typedef	signed char			int8;
91 typedef unsigned char			uint8;
92 typedef volatile signed char		vint8;
93 typedef volatile unsigned char		vuint8;
94 
95 typedef	short				int16;
96 typedef unsigned short			uint16;
97 typedef volatile short			vint16;
98 typedef volatile unsigned short		vuint16;
99 
100 typedef	long				int32;
101 typedef unsigned long			uint32;
102 typedef volatile long			vint32;
103 typedef volatile unsigned long		vuint32;
104 
105 typedef	long long			int64;
106 typedef unsigned long long		uint64;
107 typedef volatile long long		vint64;
108 typedef volatile unsigned long long	vuint64;
109 
110 typedef volatile long			vlong;
111 typedef volatile int			vint;
112 typedef volatile short			vshort;
113 typedef volatile char			vchar;
114 
115 typedef volatile unsigned long		vulong;
116 typedef volatile unsigned int		vuint;
117 typedef volatile unsigned short		vushort;
118 typedef volatile unsigned char		vuchar;
119 
120 typedef unsigned char			uchar;
121 typedef unsigned short			unichar;
122 
123 
124 
125 /*-------------------------------------------------------------*/
126 /*----- Descriptive formats -----------------------------------*/
127 typedef int32					status_t;
128 typedef int64					bigtime_t;
129 typedef uint32					type_code;
130 typedef uint32					perform_code;
131 
132 /* end nasty hack */
133 
134 #endif	/* ! B_BEOS_VERSION_5 */
135 
136 
137 #include <schily/stdlib.h>
138 #include <schily/stdio.h>
139 #include <schily/string.h>
140 #include <schily/unistd.h>
141 #include <schily/stat.h>
142 #include <scg/scgio.h>
143 
144 /* this is really really dumb (tm) */
145 /*#undef sense*/
146 /*#undef scb*/
147 #include <device/scsi.h>
148 
149 #undef bool
150 #ifdef	__HAIKU__	/* Probaby already since BeOS 5 */
151 #include <CAM.h>
152 #else
153 #include <drivers/CAM.h>
154 #endif
155 
156 struct _fdmap_ {
157 	struct _fdmap_ *next;
158 	int bus;
159 	int targ;
160 	int lun;
161 	int fd;
162 };
163 
164 /*
165  * Return version information for the low level SCSI transport code.
166  * This has been introduced to make it easier to trace down problems
167  * in applications.
168  */
169 LOCAL char *
scgo_version(scgp,what)170 scgo_version(scgp, what)
171 	SCSI	*scgp;
172 	int	what;
173 {
174 	if (scgp != (SCSI *)0) {
175 		switch (what) {
176 
177 		case SCG_VERSION:
178 			return (_scg_trans_version);
179 		/*
180 		 * If you changed this source, you are not allowed to
181 		 * return "schily" for the SCG_AUTHOR request.
182 		 */
183 		case SCG_AUTHOR:
184 			return (_scg_auth_schily);
185 		case SCG_SCCS_ID:
186 			return (__sccsid);
187 		}
188 	}
189 	return ((char *)0);
190 }
191 
192 LOCAL int
scgo_help(scgp,f)193 scgo_help(scgp, f)
194 	SCSI	*scgp;
195 	FILE	*f;
196 {
197 	__scg_help(f, "CAM", "Generic transport independent SCSI (BeOS CAM variant)",
198 		"", "bus,target,lun", "1,2,0", TRUE, FALSE);
199 	return (0);
200 }
201 
202 LOCAL int
scgo_open(scgp,device)203 scgo_open(scgp, device)
204 	SCSI	*scgp;
205 	char	*device;
206 {
207 	int	busno	= scg_scsibus(scgp);
208 	int	tgt	= scg_target(scgp);
209 #ifdef	nonono
210 	int	tlun	= scg_lun(scgp);
211 #endif
212 
213 #ifdef	nonono
214 	if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
215 		errno = EINVAL;
216 		if (scgp->errstr)
217 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
218 				"Illegal value for busno, target or lun '%d,%d,%d'",
219 				busno, tgt, tlun);
220 		return (-1);
221 	}
222 #endif
223 
224 	if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
225 		errno = EINVAL;
226 		if (scgp->errstr)
227 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
228 				"Open by 'devname' not supported on this OS");
229 		return (-1);
230 	}
231 	return (1);
232 }
233 
234 LOCAL int
scgo_close(scgp)235 scgo_close(scgp)
236 	SCSI	*scgp;
237 {
238 	struct _fdmap_	*f;
239 	struct _fdmap_	*fnext;
240 
241 	for (f = (struct _fdmap_ *)scgp->local; f; f = fnext) {
242 		scgp->local = 0;
243 		fnext = f->next;
244 		close(f->fd);
245 		free(f);
246 	}
247 	return (0);
248 }
249 
250 LOCAL long
scgo_maxdma(scgp,amt)251 scgo_maxdma(scgp, amt)
252 	SCSI	*scgp;
253 	long	amt;
254 {
255 	return (128*1024);
256 	return (256*1024);
257 }
258 
259 LOCAL void *
scgo_getbuf(scgp,amt)260 scgo_getbuf(scgp, amt)
261 	SCSI	*scgp;
262 	long	amt;
263 {
264 	if (scgp->debug > 0) {
265 		js_fprintf((FILE *)scgp->errfile,
266 			"scgo_getbuf: %ld bytes\n", amt);
267 	}
268 	scgp->bufbase = malloc((size_t)(amt));
269 	return (scgp->bufbase);
270 }
271 
272 LOCAL void
scgo_freebuf(scgp)273 scgo_freebuf(scgp)
274 	SCSI	*scgp;
275 {
276 	if (scgp->bufbase)
277 		free(scgp->bufbase);
278 	scgp->bufbase = NULL;
279 }
280 
281 LOCAL int
scgo_numbus(scgp)282 scgo_numbus(scgp)
283 	SCSI	*scgp;
284 {
285 	return (16);	/* XXX we need a better way to find the # of busses */
286 }
287 
288 LOCAL BOOL
scgo_havebus(scgp,busno)289 scgo_havebus(scgp, busno)
290 	SCSI	*scgp;
291 	int	busno;
292 {
293 	struct stat	sb;
294 	char		buf[128];
295 
296 	if (busno < 8)
297 		js_snprintf(buf, sizeof (buf), "/dev/bus/scsi/%d", busno);
298 	else
299 #ifdef	__HAIKU__
300 		js_snprintf(buf, sizeof (buf), "/dev/disk/atapi/%d", busno-8);
301 #else
302 		js_snprintf(buf, sizeof (buf), "/dev/disk/ide/atapi/%d", busno-8);
303 #endif
304 	if (stat(buf, &sb))
305 		return (FALSE);
306 	return (TRUE);
307 }
308 
309 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)310 scgo_fileno(scgp, busno, tgt, tlun)
311 	SCSI	*scgp;
312 	int	busno;
313 	int	tgt;
314 	int	tlun;
315 {
316 	struct _fdmap_	*f;
317 	char		buf[128];
318 	int		fd;
319 
320 	for (f = (struct _fdmap_ *)scgp->local; f; f = f->next) {
321 		if (f->bus == busno && f->targ == tgt && f->lun == tlun)
322 			return (f->fd);
323 	}
324 	if (busno < 8) {
325 		js_snprintf(buf, sizeof (buf),
326 					"/dev/bus/scsi/%d/%d/%d/raw",
327 					busno, tgt, tlun);
328 	} else {
329 		char *tgtstr = (tgt == 0) ? "master" : (tgt == 1) ? "slave" : "dummy";
330 		js_snprintf(buf, sizeof (buf),
331 #ifdef	__HAIKU__
332 					"/dev/disk/atapi/%d/%s/raw",
333 					busno-8, tgtstr);
334 #else
335 					"/dev/disk/ide/atapi/%d/%s/%d/raw",
336 					busno-8, tgtstr, tlun);
337 #endif
338 	}
339 	fd = open(buf, 0);
340 
341 	if (fd >= 0) {
342 		f = (struct _fdmap_ *) malloc(sizeof (struct _fdmap_));
343 		f->bus = busno;
344 		f->targ = tgt;
345 		f->lun = tlun;
346 		f->fd = fd;
347 		f->next = (struct _fdmap_ *)scgp->local;
348 		scgp->local = f;
349 	}
350 	return (fd);
351 }
352 
353 LOCAL int
scgo_initiator_id(scgp)354 scgo_initiator_id(scgp)
355 	SCSI	*scgp;
356 {
357 	return (-1);
358 }
359 
360 LOCAL int
scgo_isatapi(scgp)361 scgo_isatapi(scgp)
362 	SCSI	*scgp;
363 {
364 	/*
365 	 * XXX Should check for ATAPI
366 	 */
367 	return (-1);
368 }
369 
370 LOCAL int
scgo_reset(scgp,what)371 scgo_reset(scgp, what)
372 	SCSI	*scgp;
373 	int	what;
374 {
375 	errno = EINVAL;
376 	return (-1);
377 }
378 
379 LOCAL int
scgo_send(scgp)380 scgo_send(scgp)
381 	SCSI	*scgp;
382 {
383 	struct scg_cmd		*sp = scgp->scmd;
384 	int			e;
385 	int 			scsi_error;
386 	int			cam_error;
387 	raw_device_command	rdc;
388 
389 	if (scgp->fd < 0) {
390 		sp->error = SCG_FATAL;
391 		return (0);
392 	}
393 
394 	memcpy(rdc.command, &(sp->cdb), 12);
395 	rdc.command_length = sp->cdb_len;
396 	rdc.data = sp->addr;
397 	rdc.data_length = sp->size;
398 	rdc.sense_data_length = sp->sense_len;
399 	rdc.sense_data = sp->u_sense.cmd_sense;
400 	rdc.flags = sp->flags & SCG_RECV_DATA ? B_RAW_DEVICE_DATA_IN : 0;
401 	if (sp->size > 0)
402 		rdc.flags |= B_RAW_DEVICE_REPORT_RESIDUAL;
403 	rdc.timeout = sp->timeout * 1000000;
404 
405 	sp->error		= SCG_NO_ERROR;
406 	sp->sense_count		= 0;
407 	sp->u_scb.cmd_scb[0]	= 0;
408 	sp->resid		= 0;
409 
410 	if (scgp->debug > 0) {
411 		error("SEND(%d): cmd %02x, cdblen = %d, datalen = %ld, senselen = %ld\n",
412 			scgp->fd, rdc.command[0], rdc.command_length,
413 			rdc.data_length, rdc.sense_data_length);
414 	}
415 	e = ioctl(scgp->fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof (rdc));
416 	if (scgp->debug > 0) {
417 		error("SEND(%d): -> %d CAM Status %02X SCSI status %02X\n", e, rdc.cam_status, rdc.scsi_status);
418 	}
419 	sp->ux_errno = 0;
420 #ifdef	DEBUG
421 	error("err %d errno %x CAM %X SL %d DL %d/%d FL %X\n",
422 		e, geterrno(), rdc.cam_status,
423 		rdc.sense_data_length, rdc.data_length, sp->size, rdc.flags);
424 #endif
425 	if (!e) {
426 		cam_error = rdc.cam_status;
427 		scsi_error = rdc.scsi_status;
428 		sp->u_scb.cmd_scb[0] = scsi_error;
429 		if (sp->size > 0)
430 			sp->resid = sp->size - rdc.data_length;
431 
432 		switch (cam_error & CAM_STATUS_MASK) {
433 
434 		case CAM_REQ_CMP:
435 			sp->error = SCG_NO_ERROR;
436 			break;
437 
438 		case CAM_REQ_CMP_ERR:
439 			sp->sense_count = sp->sense_len; /* XXX */
440 			sp->error = SCG_NO_ERROR;
441 			sp->ux_errno = EIO;
442 			break;
443 
444 		case CAM_CMD_TIMEOUT:
445 			sp->error = SCG_TIMEOUT;
446 			sp->ux_errno = EIO;
447 
448 		case CAM_SEL_TIMEOUT:
449 			sp->error = SCG_FATAL;
450 			sp->ux_errno = EIO;
451 			break;
452 
453 		default:
454 			sp->error = SCG_RETRYABLE;
455 			sp->ux_errno = EIO;
456 		}
457 	} else {
458 		sp->error = SCG_FATAL;
459 		sp->ux_errno = geterrno();
460 		sp->resid = sp->size;
461 	}
462 	return (0);
463 }
464