1 /* @(#)scsi-atari.c	1.3 09/07/13 Copyright 1997,2000,2009 J. Schilling */
2 #ifndef lint
3 static	char __sccsid[] =
4 	"@(#)scsi-atari.c	1.3 09/07/13 Copyright 1997,2000,2009 J. Schilling";
5 #endif
6 /*
7  *	Interface for Atari generic SCSI implementation.
8  *
9  *	Copyright (c) 1997, 2000, 2009 J. Schilling
10  *	Atari systems support code written by Yvan Doyeux
11  *
12  *
13  *  SCSIDRV driver is needed to enable libscg on Atari computers.
14  *  I need to pass through assembler to avoid using of -mshort GCC option.
15  *  Actually SCSIDRV requires real 16-bit word for several function arguments.
16  *
17  *  If you are using HDDRIVER, it already includes the SCSIDRV programming interface,
18  *  otherwise you must run SCSIDRV.PRG before.
19  *
20  *  The following bus-numbers are reserved for this:
21  *  0 (ACSI)
22  *  1 (Standard SCSI: Falcon, TT, Medusa, MagicMac...)
23  *  2 (IDE in Atari-compatibles)
24  *
25  *  For further information, see packages SCSIDRV.ZIP and CBHD502.ZIP.
26  *
27  *	Warning: you may change this source, but if you do that
28  *	you need to change the _scg_version and _scg_auth* string below.
29  *	You may not return "schily" for an SCG_AUTHOR request anymore.
30  *	Choose your name instead of "schily" and make clear that the version
31  *	string is related to a modified source.
32  */
33 /*
34  * The contents of this file are subject to the terms of the
35  * Common Development and Distribution License, Version 1.0 only
36  * (the "License").  You may not use this file except in compliance
37  * with the License.
38  *
39  * See the file CDDL.Schily.txt in this distribution for details.
40  * A copy of the CDDL is also available via the Internet at
41  * http://www.opensource.org/licenses/cddl1.txt
42  *
43  * The following exceptions apply:
44  * CDDL �3.6 needs to be replaced by: "You may create a Larger Work by
45  * combining Covered Software with other code if all other code is governed by
46  * the terms of a license that is OSI approved (see www.opensource.org) and
47  * you may distribute the Larger Work as a single product. In such a case,
48  * You must make sure the requirements of this License are fulfilled for
49  * the Covered Software."
50  *
51  * When distributing Covered Code, include this CDDL HEADER in each
52  * file and include the License file CDDL.Schily.txt from this distribution.
53  */
54 
55 #include <schily/stdio.h>
56 #include <schily/string.h>
57 #include <osbind.h>
58 #include <schily/signal.h>
59 #include <schily/stdlib.h>
60 
61 #define	cdecl
62 
63 #define	BOOLEAN	long
64 #define	BYTE	char			/* Signed byte			*/
65 #define	UBYTE	unsigned char		/* Unsigned byte		*/
66 #define	WORD	short			/* Signed word (16 bits)	*/
67 #define	UWORD	unsigned short		/* Unsigned word		*/
68 
69 #define	SCSIRevision 0x0101
70 
71 #define	MAXBUSNO	31
72 #define	MAX_SCSIDRV_HANDLE    32
73 
74 #define	MAX_SCG		3	/* Max # of SCSI controllers */
75 #define	MAX_TGT		8
76 #define	MAX_LUN		1
77 
78 /*
79  * SCSIDRV return values
80  */
81 #define	CHECKCONDITION	 2L
82 #define	NOSCSIERROR	 0L
83 #define	SELECTERROR	-1L
84 #define	STATUSERROR	-2L
85 #define	PHASEERROR	-3L
86 #define	BSYERROR	-4L
87 #define	BUSERROR	-5L
88 #define	TRANSERROR	-6L
89 #define	FREEERROR	-7L
90 #define	TIMEOUTERROR	-8L
91 #define	DATATOOLONG	-9L
92 #define	LINKERROR	-10L
93 #define	TIMEOUTARBIT	-11L
94 #define	PENDINGERROR	-12L
95 #define	PARITYERROR	-13L
96 
97 LOCAL	char	_scg_trans_version[] = "scsi-atari.c-1.3";	/* The version for this transport */
98 LOCAL	char	_scg_auth[] = "Yvan Doyeux";
99 
100 
101 typedef struct {
102 	unsigned long	hi;
103 	unsigned long	lo;
104 } DLONG;
105 
106 typedef struct {
107 	unsigned long	BusIds;
108 	BYTE		resrvd[28];
109 } tPrivate;
110 
111 typedef WORD *tHandle;
112 
113 typedef struct {
114 	tHandle		Handle;
115 	BYTE		*Cmd;
116 	UWORD		CmdLen;
117 	void		*Buffer;
118 	unsigned long	TransferLen;
119 	BYTE		*SenseBuffer;
120 	unsigned long	Timeout;
121 	UWORD		Flags;
122 #define	Disconnect	0x10
123 } tSCSICmd;
124 typedef tSCSICmd *tpSCSICmd;
125 
126 
127 typedef struct {
128 	tPrivate	Private;
129 	char		BusName[20];
130 	UWORD		BusNo;
131 	UWORD		Features;
132 #define	cArbit		0x01
133 #define	cAllCmds	0x02
134 #define	cTargCtrl	0x04
135 #define	cTarget		0x08
136 #define	cCanDisconnect	0x10
137 #define	cScatterGather	0x20
138 	unsigned long	MaxLen;
139 } tBusInfo;
140 
141 
142 typedef struct {
143 	BYTE	Private[32];
144 	DLONG	SCSIId;
145 } tDevInfo;
146 
147 
148 typedef struct ttargethandler {
149 	struct  ttargethandler *next;
150 	BOOLEAN cdecl (*TSel) 	(WORD bus, UWORD CSB, UWORD CSD);
151 	BOOLEAN cdecl (*TCmd) 	(WORD bus, BYTE	*Cmd);
152 	UWORD   cdecl (*TCmdLen) (WORD bus, UWORD Cmd);
153 	void	cdecl (*TReset)	(UWORD bus);
154 	void	cdecl (*TEOP) 	(UWORD bus);
155 	void	cdecl (*TPErr)	(UWORD bus);
156 	void	cdecl (*TPMism)	(UWORD bus);
157 	void	cdecl (*TBLoss)	(UWORD bus);
158 	void	cdecl (*TUnknownInt) (UWORD bus);
159 } tTargetHandler;
160 
161 typedef tTargetHandler *tpTargetHandler;
162 
163 typedef BYTE tReqData[18];
164 
165 typedef struct
166 {
167 	UWORD	Version;
168 
169 				/* Routinen als Initiator */
170 	long	cdecl (*In)	(tpSCSICmd Parms);
171 	long	cdecl (*Out)	(tpSCSICmd Parms);
172 
173 	long	cdecl (*InquireSCSI)	(WORD what, tBusInfo *Info);
174 #define	cInqFirst	0
175 #define	cInqNext	1
176 	long	cdecl (*InquireBus)	(WORD what, WORD BusNo, tDevInfo *Dev);
177 	long	cdecl (*CheckDev)	(WORD BusNo, const DLONG *SCSIId, char *Name, UWORD *Features);
178 	long	cdecl (*RescanBus)	(WORD BusNo);
179 	long	cdecl (*Open)		(WORD BusNo, const DLONG *SCSIId, unsigned long *MaxLen);
180 	long	cdecl (*Close)		(tHandle handle);
181 	long	cdecl (*Error)		(tHandle handle, WORD rwflag, WORD ErrNo);
182 #define	cErrRead	0
183 #define	cErrWrite	1
184 #define	cErrMediach	0
185 #define	cErrReset	1
186 
187 	long	cdecl (*Install)	(WORD bus, tpTargetHandler Handler);
188 	long	cdecl (*Deinstall)	(WORD bus, tpTargetHandler Handler);
189 	long	cdecl (*GetCmd)		(WORD bus, BYTE *Cmd);
190 	long	cdecl (*SendData)	(WORD bus, BYTE *Buffer, unsigned long Len);
191 	long	cdecl (*GetData)	(WORD bus, void *Buffer, unsigned long Len);
192 	long	cdecl (*SendStatus)	(WORD bus, UWORD Status);
193 	long	cdecl (*SendMsg)	(WORD bus, UWORD Msg);
194 	long	cdecl (*GetMsg)		(WORD bus, UWORD *Msg);
195 
196 	tReqData	*ReqData;
197 } tScsiCall;
198 
199 typedef tScsiCall *tpScsiCall;
200 
201 
202 LOCAL	int	num_handle_opened = 0;
203 LOCAL	tHandle tab_handle_opened[MAX_SCSIDRV_HANDLE];
204 LOCAL	SCSI	*scgp_local;
205 
206 tpScsiCall scsicall;
207 
208 struct bus_struct {
209 	tBusInfo bus;
210 	tDevInfo *dev[MAX_TGT];
211 };
212 
213 struct	scg_local {
214 		struct bus_struct *atari_bus[MAX_SCG];
215 };
216 
217 #define	scglocal(p)	((struct scg_local *)((p)->local))
218 
219 /*
220  * Return version information for the low level SCSI transport code.
221  * This has been introduced to make it easier to trace down problems
222  * in applications.
223  */
224 LOCAL char *
scgo_version(scgp,what)225 scgo_version(scgp, what)
226 	SCSI	*scgp;
227 	int	what;
228 {
229 	if (scgp != (SCSI *)0) {
230 		switch (what) {
231 
232 		case SCG_VERSION:
233 			return (_scg_trans_version);
234 		/*
235 		 * If you changed this source, you are not allowed to
236 		 * return "schily" for the SCG_AUTHOR request.
237 		 */
238 		case SCG_AUTHOR:
239 			return (_scg_auth);
240 		case SCG_SCCS_ID:
241 			return (__sccsid);
242 		}
243 	}
244 	return ((char *)0);
245 }
246 
247 
248 
249 LOCAL int
scgo_help(scgp,f)250 scgo_help(scgp, f)
251 	SCSI	*scgp;
252 	FILE	*f;
253 {
254 	__scg_help(f, "SCSIDRV Interface", "Atari generic SCSI implementation",
255 		"", "bus,target,lun", "1,2,0", TRUE, FALSE);
256 	printf("\nSCSIDRV driver is needed to enable libscg on Atari computers.\n");
257 	printf("If you are using HDDRIVER, it already includes the SCSIDRV\n");
258 	printf("programming interface otherwise you must run SCSIDRV.PRG before.\n");
259 	printf("The following bus-numbers are reserved for this:\n");
260 	printf("0 (ACSI)\n");
261 	printf("1 (Standard SCSI: Falcon, TT, Medusa, MagicMac...)\n");
262 	printf("2 (IDE in Atari-compatibles)\n");
263 	printf("For further information, see packages SCSIDRV.ZIP and CBHD502.ZIP.\n");
264 
265 	return (0);
266 }
267 
268 
269 LOCAL void
scsidrv_close()270 scsidrv_close()
271 {
272 	long	rc;
273 
274 	rc = (long)scsicall->Close;
275 	{
276 	register long retvalue __asm__("d0");
277 
278 	/* BEGIN CSTYLED */
279 	__asm__ volatile ("
280 		movl	%1,sp@-;
281 		jbsr	(%2);
282 		lea	sp@(4),sp "
283 	: "=r"(retvalue)			/* outputs */
284 	: "r"((tHandle) scgp_local->fd),"a"(rc)	/* inputs  */
285 	: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
286 	AND_MEMORY);
287 	/* END CSTYLED */
288 	}
289 
290 	num_handle_opened = num_handle_opened - 1;
291 	if ((num_handle_opened-1) >= 0)
292 		scgp_local->fd = (int)tab_handle_opened[num_handle_opened-1];
293 	else
294 		scgp_local->fd = 0;
295 }
296 
297 LOCAL void
atari_free_scsi_all()298 atari_free_scsi_all()
299 {
300 	int	i;
301 	int	j;
302 
303 	for (j = 0; j < MAX_SCG; j++) {
304 		if (scglocal(scgp_local)->atari_bus[j] != (struct bus_struct *)-1) {
305 			for (i = 0; i < MAX_TGT; i++) {
306 				if (scglocal(scgp_local)->atari_bus[j]->dev[i] != (tDevInfo *)-1) {
307 					free(scglocal(scgp_local)->atari_bus[j]->dev[i]);
308 				}
309 			}
310 			free(scglocal(scgp_local)->atari_bus[j]);
311 		}
312 	}
313 	if (scgp_local->local) {
314 		free(scgp_local->local);
315 	}
316 
317 	scgo_freebuf(scgp_local);
318 }
319 
320 
321 
322 LOCAL int
scgo_open(scgp,device)323 scgo_open(scgp, device)
324 	SCSI	*scgp;
325 	char	*device;
326 
327 {
328 	/* SCSIDRV present ? */
329 	BOOL		scsidrv = FALSE;
330 	BOOL		nopen = FALSE;
331 	void		*oldstack;
332 	long		rc_bus;
333 	int		i;
334 	int		j;
335 	tBusInfo	Bus;
336 	WORD		Inq_bus = cInqFirst;
337 	long		cookie_value;
338 
339 	scsicall = NULL;
340 	scgp_local = scgp;
341 
342 	if (Getcookie(0x53435349L, &cookie_value) == 0) {
343 		scsicall = (tpScsiCall)cookie_value;
344 		printf("SCSIDRV found on your ATARI!\n");
345 		scsidrv = TRUE;
346 	} else {
347 		printf("I can't find SCSIDRV on your ATARI...\n");
348 		scsidrv = FALSE;
349 		nopen = FALSE;
350 	}
351 
352 
353 	if (scsidrv == TRUE) {
354 		if (scgp->local == NULL) {
355 			scgp->local = malloc(sizeof (struct scg_local));
356 			if (scgp->local == NULL)
357 				return (0);
358 			for (j = 0; j < MAX_SCG; j++) {
359 				scglocal(scgp)->atari_bus[j] = (struct bus_struct *)-1;
360 			}
361 		}
362 
363 
364 
365 	oldstack = (void *)Super(NULL);
366 	rc_bus = (long)scsicall->InquireSCSI; /* busses available */
367 	/*
368 	 * InquireSCSI
369 	 */
370 	{
371 	register long ret_bus_value __asm__("d0") = 0; /* Return of InquireSCSI */
372 	long ret_bus = 0;
373 
374 	while (ret_bus == 0) {
375 
376 	/* BEGIN CSTYLED */
377 	__asm__ volatile ("
378 		movl	%1,sp@-;	/* Pointer of bus structure (32-bit long)*/
379 		movw	%3,sp@-;	/* Inq_bus argument (16-bit WORD) */
380 		jbsr	(%2);		/* Call to InquireSCSI SCSIDRV function */
381 		lea	sp@(6),sp	/* Fix the stack */ "
382 	: "=r"(ret_bus_value)			/* outputs */
383 	: "r"(&Bus),"a"(rc_bus), "r"(Inq_bus)	/* inputs  */
384 	: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
385 	AND_MEMORY);
386 	/* END CSTYLED */
387 
388 	ret_bus = ret_bus_value;
389 	if (ret_bus == 0) {
390 		scglocal(scgp)->atari_bus[Bus.BusNo] = malloc(sizeof (struct bus_struct));
391 		memcpy(&scglocal(scgp)->atari_bus[Bus.BusNo]->bus, &Bus, sizeof (tBusInfo));
392 			for (i = 0; i < MAX_TGT; i++) {
393 				scglocal(scgp)->atari_bus[Bus.BusNo]->dev[i] = (tDevInfo *)-1;
394 			}
395 
396 			{
397 			long rc_dev;
398 			WORD Inq_dev = cInqFirst;
399 			register long ret_dev_value __asm__("d0") = 0;
400 			long ret_dev = 0;
401 			tDevInfo Dev;
402 			rc_dev = (long)scsicall->InquireBus; /* we inquiry for devices in bus Bus.BusNo */
403 			while (ret_dev == 0) {
404 
405 			/* BEGIN CSTYLED */
406 			__asm__ volatile ("
407 				movl	%2,sp@-;
408 				movw	%1,sp@-;
409 				movw	%4,sp@-;
410 				jbsr	(%3);
411 				lea	sp@(8),sp "
412 			: "=r"(ret_dev_value)			/* outputs */
413 			: "r"(Bus.BusNo),"r"(&Dev),"a"(rc_dev), "r"(Inq_dev)		/* inputs  */
414 			: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
415 			AND_MEMORY);
416 			/* END CSTYLED */
417 
418 			ret_dev = ret_dev_value;
419 			if (ret_dev == 0) {
420 				scglocal(scgp)->atari_bus[Bus.BusNo]->dev[(int)Dev.SCSIId.lo] = malloc(sizeof (tDevInfo));
421 				memcpy(scglocal(scgp)->atari_bus[Bus.BusNo]->dev[(int)Dev.SCSIId.lo], &Dev, sizeof (tDevInfo));
422 			}
423 			Inq_dev = cInqNext;
424 			}
425 			}
426 
427 	}
428 	Inq_bus = cInqNext;
429 	}
430 	}
431 
432 
433 		Super(oldstack);
434 
435 		atexit(scsidrv_close);
436 		atexit(atari_free_scsi_all);
437 
438 		nopen = TRUE;
439 	}
440 	return (nopen);
441 
442 }
443 
444 
445 
446 LOCAL int
scgo_close(SCSI * scgp)447 scgo_close(SCSI * scgp)
448 {
449 	scsidrv_close();
450 	atari_free_scsi_all();
451 	return (0);
452 }
453 
454 
455 LOCAL long
scgo_maxdma(scgp,amt)456 scgo_maxdma(scgp, amt)
457 	SCSI	*scgp;
458 	long	amt;
459 {
460 	/* return (63*1024); */
461 	return (256*1024);
462 }
463 
464 
465 
466 LOCAL void *
scgo_getbuf(scgp,amt)467 scgo_getbuf(scgp, amt)
468 	SCSI	*scgp;
469 	long	amt;
470 {
471 	if (scgp->debug > 0) {
472 		js_fprintf((FILE *)scgp->errfile,
473 			"scgo_getbuf: %ld bytes\n", amt);
474 	}
475 	scgp->bufbase = malloc((size_t)(amt));
476 	return (scgp->bufbase);
477 
478 }
479 
480 
481 
482 LOCAL void
scgo_freebuf(scgp)483 scgo_freebuf(scgp)
484 	SCSI	*scgp;
485 {
486 	if (scgp->bufbase)
487 		free(scgp->bufbase);
488 	scgp->bufbase = NULL;
489 }
490 
491 
492 
493 
494 LOCAL int
scgo_numbus(scgp)495 scgo_numbus(scgp)
496 	SCSI	*scgp;
497 {
498 	return (MAX_SCG);
499 }
500 
501 
502 
503 LOCAL BOOL
scgo_havebus(scgp,busno)504 scgo_havebus(scgp, busno)
505 	SCSI	*scgp;
506 	int	busno;
507 {
508 	return (TRUE);
509 }
510 
511 
512 
513 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)514 scgo_fileno(scgp, busno, tgt, tlun)
515 	SCSI	*scgp;
516 	int	busno;
517 	int	tgt;
518 	int	tlun;
519 {
520 	long		rc;
521 	unsigned long	MaxLen;
522 	int		fd = 0;
523 	tBusInfo	Bus;
524 	void		*oldstack;
525 
526 	if (scgp_local->fd > 0) {	/* handle exists ? */
527 		scsidrv_close();
528 	}
529 
530 	if (busno < 0 || busno >= MAX_SCG ||
531 	    tgt < 0 || tgt >= MAX_TGT ||
532 	    tlun < 0 || tlun >= MAX_LUN) {
533 		errno = EINVAL;
534 		return (-1);
535 	}
536 
537 	if (scglocal(scgp)->atari_bus[busno] == (struct bus_struct *)-1) {
538 		errno = EINVAL;
539 		return (-1);
540 	}
541 
542 	if ((struct tDevInfo *) scglocal(scgp)->atari_bus[busno]->dev[tgt] == (struct tDevInfo *)-1) {
543 		errno = EINVAL;
544 		return (-1);
545 	}
546 
547 
548 	oldstack = (void *)Super(NULL);
549 	rc = (long)scsicall->Open;
550 	{
551 	register long retvalue __asm__("d0") = 0;
552 
553 	/* BEGIN CSTYLED */
554 	__asm__ volatile ("
555 		movl	%3,sp@-;
556 		movl	%2,sp@-;
557 		movw	%1,sp@-;
558 		jbsr	(%4);
559 		lea	sp@(10),sp "
560 	: "=r"(retvalue)			/* outputs */
561 	: "r"(scglocal(scgp)->atari_bus[busno]->bus.BusNo),
562 	"r"(&scglocal(scgp)->atari_bus[busno]->dev[tgt]->SCSIId),"r"(&MaxLen),"a"(rc)		/* inputs  */
563 	: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
564 	AND_MEMORY);
565 	/* END CSTYLED */
566 
567 	fd = (int)retvalue;
568 	}
569 
570 
571 	Super(oldstack);
572 
573 	if (fd > 0) {
574 		tab_handle_opened[num_handle_opened] = (tHandle)fd;
575 		num_handle_opened = num_handle_opened + 1;
576 		return (fd);
577 	} else {
578 		return (-1);
579 	}
580 }
581 
582 
583 LOCAL int
scgo_initiator_id(scgp)584 scgo_initiator_id(scgp)
585 	SCSI	*scgp;
586 {
587 	return (-1);
588 }
589 
590 
591 LOCAL int
scgo_isatapi(scgp)592 scgo_isatapi(scgp)
593 	SCSI	*scgp;
594 {
595 	return (FALSE);
596 }
597 
598 
599 
600 LOCAL int
scgo_reset(scgp,what)601 scgo_reset(scgp, what)
602 	SCSI	*scgp;
603 	int	what;
604 {
605 	/* XXX synchronous reset command - is this wise? */
606 	errno = EINVAL;
607 	return (-1);
608 }
609 
610 
611 LOCAL int
scgo_send(scgp)612 scgo_send(scgp)
613 	SCSI	*scgp;
614 {
615 	long		rc;
616 	void		*oldstack;
617 	tSCSICmd	cmd;
618 	tBusInfo	Bus;
619 	tDevInfo	Dev;
620 	unsigned long	MaxLen;
621 	long		ret = 0;
622 	BYTE		reqbuff[18];
623 
624 	scgp->scmd->ux_errno = 0;
625 
626 	if (scgp->fd <= 0) {
627 		scgp->scmd->error = SCG_FATAL;
628 		return (0);
629 	}
630 
631 
632 	oldstack = (void *)Super(NULL);
633 	cmd.Handle = (tHandle) scgp->fd;
634 	cmd.Cmd = malloc(scgp->scmd->cdb_len);
635 	movebytes(&scgp->scmd->cdb, cmd.Cmd, scgp->scmd->cdb_len);
636 	cmd.CmdLen = /* (UWORD) */ scgp->scmd->cdb_len;
637 	cmd.Buffer = scgp->scmd->addr;
638 	cmd.TransferLen = scgp->scmd->size;
639 	cmd.SenseBuffer = scgp->scmd->u_sense.cmd_sense;
640 	fillbytes(cmd.SenseBuffer, sizeof (reqbuff), '\0');
641 	cmd.Timeout = scgp->scmd->timeout * 200;
642 	cmd.Flags = scgp->scmd->flags & SCG_RECV_DATA;
643 	scgp->scmd->u_scb.cmd_scb[0] = 0;
644 
645 
646 	if ((scgp->scmd->flags & SCG_RECV_DATA)) {
647 		rc = (long)scsicall->In;
648 	{
649 	register long retvalue __asm__("d0");
650 
651 	/* BEGIN CSTYLED */
652 	__asm__ volatile ("
653 		movl	%1,sp@-;
654 		jbsr	(%2);
655 		lea	sp@(4),sp "
656 	: "=r"(retvalue)			/* outputs */
657 	: "r"(&cmd),"a"(rc)			/* inputs  */
658 	: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
659 	AND_MEMORY);
660 	/* END CSTYLED */
661 
662 	ret = retvalue;
663 	}
664 	} else if (scgp->scmd->size > 0) {
665 
666 	rc = (long)scsicall->Out;
667 	{
668 	register long retvalue __asm__("d0");
669 
670 	/* BEGIN CSTYLED */
671 	__asm__ volatile ("
672 		movl	%1,sp@-;
673 		jbsr	(%2);
674 		lea	sp@(4),sp "
675 	: "=r"(retvalue)			/* outputs */
676 	: "r"(&cmd),"a"(rc)			/* inputs  */
677 	: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
678 	AND_MEMORY);
679 	/* END CSTYLED */
680 
681 	ret = retvalue;
682 	}
683 	} else {
684 
685 		rc = (long)scsicall->Out;
686 		{
687 		register long retvalue __asm__("d0");
688 
689 		/* BEGIN CSTYLED */
690 		__asm__ volatile ("
691 			movl	%1,sp@-;
692 			jbsr	(%2);
693 			lea	sp@(4),sp "
694 		: "=r"(retvalue)			/* outputs */
695 		: "r"(&cmd),"a"(rc)			/* inputs  */
696 		: "d0", "d1", "d2", "a0", "a1", "a2"	/* clobbered regs */
697 		AND_MEMORY);
698 		/* BEGIN CSTYLED */
699 
700 		ret = retvalue;
701 		}
702 	}
703 
704 	Super(oldstack);
705 
706 	scgp->scmd->resid = 0;
707 
708 	scgp->scmd->sense_count = sizeof (reqbuff);	/* 18 */
709 	movebytes(cmd.SenseBuffer, &scgp->scmd->u_sense.cmd_sense, sizeof (reqbuff));
710 
711 	free(cmd.Cmd);
712 
713 	scgp->scmd->u_scb.cmd_scb[0] = ret;
714 
715 
716 	switch (ret) {
717 	case CHECKCONDITION:
718 	    scgp->scmd->ux_errno = geterrno();
719 	    scgp->scmd->error = SCG_NO_ERROR;
720 	    break;
721 	case TIMEOUTERROR:
722 	    scgp->scmd->ux_errno = geterrno();
723 	    scgp->scmd->error = SCG_TIMEOUT;
724 	    break;
725 	default:
726 	    if (ret < 0)
727 	    {
728 		scgp->scmd->ux_errno = geterrno();
729 		scgp->scmd->error = SCG_FATAL;
730 	    }
731 	    else
732 		scgp->scmd->error = SCG_NO_ERROR;
733 		break;
734 	}
735 
736 	return (ret);
737 }
738