1 /* @(#)scsi-syllable.c	1.2 12/12/02 Copyright 1998-2012 J. Schilling, 2005 Kristian Van Der Vliet */
2 #ifndef lint
3 static	char sccsid[] =
4 	"@(#)scsi-syllable.c	1.2 12/12/02 Copyright 1998-2012 J. Schilling, 2005 Kristian Van Der Vliet";
5 #endif
6 /*
7  *	Interface for the Syllable "SCSI" implementation.
8  *
9  *	Current versions of Syllable do not implement a complete SCSI layer,
10  *	but the ATAPI portion of the ATA driver has a simple interface that
11  *	can be used to send raw ATAPI packets to the device.
12  *
13  *	This drives can be seen only as a first hack. As it does not support
14  *	SCSI bus scanning, there is not yet support for the auto-target
15  *	feature os higher level applications.
16  *
17  *	Warning: you may change this source, but if you do that
18  *	you need to change the _scg_version and _scg_auth* string below.
19  *	You may not return "schily" for an SCG_AUTHOR request anymore.
20  *	Choose your name instead of "schily" and make clear that the version
21  *	string is related to a modified source.
22  *
23  *	Copyright (c) 1998-2012 J. Schilling
24  */
25 /*
26  * The contents of this file are subject to the terms of the
27  * Common Development and Distribution License, Version 1.0 only
28  * (the "License").  You may not use this file except in compliance
29  * with the License.
30  *
31  * See the file CDDL.Schily.txt in this distribution for details.
32  * A copy of the CDDL is also available via the Internet at
33  * http://www.opensource.org/licenses/cddl1.txt
34  *
35  * The following exceptions apply:
36  * CDDL �3.6 needs to be replaced by: "You may create a Larger Work by
37  * combining Covered Software with other code if all other code is governed by
38  * the terms of a license that is OSI approved (see www.opensource.org) and
39  * you may distribute the Larger Work as a single product. In such a case,
40  * You must make sure the requirements of this License are fulfilled for
41  * the Covered Software."
42  *
43  * When distributing Covered Code, include this CDDL HEADER in each
44  * file and include the License file CDDL.Schily.txt from this distribution.
45  */
46 
47 /*
48  *	Warning: you may change this source, but if you do that
49  *	you need to change the _scg_version and _scg_auth* string below.
50  *	You may not return "schily" for an SCG_AUTHOR request anymore.
51  *	Choose your name instead of "schily" and make clear that the version
52  *	string is related to a modified source.
53  */
54 LOCAL	char	_scg_trans_version[] = "scsi-syllable.c-1.2"; /* The version for this transport */
55 
56 #include <schily/stdlib.h>
57 #include <schily/stdio.h>
58 #include <schily/string.h>
59 #include <schily/unistd.h>
60 #include <schily/stat.h>
61 #ifdef	__PYRO__		/* Pyro */
62 #include <pyro/types.h>
63 #include <pyro/cdrom.h>
64 #else				/* Syllable and AtheOS */
65 #include <atheos/types.h>
66 #include <atheos/cdrom.h>
67 #endif
68 
69 #define	MAX_SCG		16	/* Max # of SCSI controllers */
70 
71 struct scg_local {
72 	int		fd;
73 };
74 
75 #define	scglocal(p)	((struct scg_local *)((p)->local))
76 
77 /*
78  * Return version information for the low level SCSI transport code.
79  * This has been introduced to make it easier to trace down problems
80  * in applications.
81  */
82 LOCAL char *
scgo_version(scgp,what)83 scgo_version(scgp, what)
84 	SCSI	*scgp;
85 	int	what;
86 {
87 	if (scgp != (SCSI *)0) {
88 		switch (what) {
89 
90 		case SCG_VERSION:
91 			return (_scg_trans_version);
92 		case SCG_AUTHOR:
93 			return ("vanders");
94 		case SCG_SCCS_ID:
95 			return (__sccsid);
96 		}
97 	}
98 	return ((char *)0);
99 }
100 
101 LOCAL int
scgo_help(scgp,f)102 scgo_help(scgp, f)
103 	SCSI	*scgp;
104 	FILE	*f;
105 {
106 	__scg_help(f, "ATA", "ATA Packet SCSI transport",
107 		"ATAPI:", "device", "/dev/disk/ata/cdc/raw", FALSE, TRUE);
108 	return (0);
109 }
110 
111 LOCAL int
scgo_open(scgp,device)112 scgo_open(scgp, device)
113 	SCSI	*scgp;
114 	char	*device;
115 {
116 	int	fd;
117 
118 	if (device == NULL || *device == '\0') {
119 		errno = EINVAL;
120 		if (scgp->errstr)
121 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
122 				"'devname' must be specified on this OS");
123 		return (-1);
124 	}
125 
126 	if (scgp->local == NULL) {
127 		scgp->local = malloc(sizeof (struct scg_local));
128 		if (scgp->local == NULL)
129 			return (0);
130 		scglocal(scgp)->fd = -1;
131 	}
132 
133 	if (scglocal(scgp)->fd != -1)	/* multiple open? */
134 		return (1);
135 
136 	if ((scglocal(scgp)->fd = open(device, O_RDONLY, 0)) < 0) {
137 		if (scgp->errstr)
138 			js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
139 				"Cannot open '%s'", device);
140 		return (-1);
141 	}
142 
143 	scg_settarget(scgp, 0, 0, 0);
144 
145 	return (1);
146 }
147 
148 LOCAL int
scgo_close(scgp)149 scgo_close(scgp)
150 	SCSI	*scgp;
151 {
152 	if (scgp->local == NULL)
153 		return (-1);
154 
155 	if (scglocal(scgp)->fd >= 0)
156 		close(scglocal(scgp)->fd);
157 	scglocal(scgp)->fd = -1;
158 	return (0);
159 }
160 
161 LOCAL long
scgo_maxdma(scgp,amt)162 scgo_maxdma(scgp, amt)
163 	SCSI	*scgp;
164 	long	amt;
165 {
166 	return (256*1024);
167 }
168 
169 LOCAL void *
scgo_getbuf(scgp,amt)170 scgo_getbuf(scgp, amt)
171 	SCSI	*scgp;
172 	long	amt;
173 {
174 	if (scgp->debug > 0) {
175 		js_fprintf((FILE *)scgp->errfile,
176 			"scgo_getbuf: %ld bytes\n", amt);
177 	}
178 	scgp->bufbase = malloc((size_t)(amt));
179 	return (scgp->bufbase);
180 }
181 
182 LOCAL void
scgo_freebuf(scgp)183 scgo_freebuf(scgp)
184 	SCSI	*scgp;
185 {
186 	if (scgp->bufbase)
187 		free(scgp->bufbase);
188 	scgp->bufbase = NULL;
189 }
190 
191 LOCAL int
scgo_numbus(scgp)192 scgo_numbus(scgp)
193 	SCSI	*scgp;
194 {
195 	return (MAX_SCG);
196 }
197 
198 LOCAL BOOL
scgo_havebus(scgp,busno)199 scgo_havebus(scgp, busno)
200 	SCSI	*scgp;
201 	int	busno;
202 {
203 	return (TRUE);
204 }
205 
206 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)207 scgo_fileno(scgp, busno, tgt, tlun)
208 	SCSI	*scgp;
209 	int	busno;
210 	int	tgt;
211 	int	tlun;
212 {
213 	if (scgp->local == NULL)
214 		return (-1);
215 
216 	return ((busno < 0 || busno >= MAX_SCG) ? -1 : scglocal(scgp)->fd);
217 }
218 
219 LOCAL int
scgo_initiator_id(scgp)220 scgo_initiator_id(scgp)
221 	SCSI	*scgp;
222 {
223 	return (-1);
224 }
225 
226 LOCAL int
scgo_isatapi(scgp)227 scgo_isatapi(scgp)
228 	SCSI	*scgp;
229 {
230 	return (TRUE);
231 }
232 
233 LOCAL int
scgo_reset(scgp,what)234 scgo_reset(scgp, what)
235 	SCSI	*scgp;
236 	int	what;
237 {
238 	errno = EINVAL;
239 	return (-1);
240 }
241 
242 LOCAL int
scgo_send(scgp)243 scgo_send(scgp)
244 	SCSI	*scgp;
245 {
246 	struct scg_cmd		*sp = scgp->scmd;
247 	int			ret;
248 	cdrom_packet_cmd_s	cmd;
249 
250 	if (scgp->fd < 0) {
251 		sp->error = SCG_FATAL;
252 		return (-1);
253 	}
254 
255 	/*
256 	 * As long as we only support ATAPI, we limit the SCSI CDB size to 12.
257 	 */
258 	if (sp->cdb_len > 12) {
259 		if (scgp->debug > 0)
260 			error("sp->cdb_len > 12!\n");
261 		sp->error = SCG_FATAL;
262 		sp->ux_errno = EIO;
263 		return (0);
264 	}
265 
266 	/* initialize */
267 	fillbytes((caddr_t) & cmd, sizeof (cmd), '\0');
268 	fillbytes((caddr_t) & sp->u_sense.cmd_sense,
269 					sizeof (sp->u_sense.cmd_sense), '\0');
270 
271 	memcpy(cmd.nCommand, &(sp->cdb), sp->cdb_len);
272 	cmd.nCommandLength = sp->cdb_len;
273 	cmd.pnData = (uint8 *)sp->addr;
274 	cmd.nDataLength = sp->size;
275 	cmd.pnSense = (uint8 *)sp->u_sense.cmd_sense;
276 	cmd.nSenseLength = sp->sense_len;
277 	cmd.nFlags = 0;
278 
279 	if (sp->size > 0) {
280 		if (sp->flags & SCG_RECV_DATA)
281 			cmd.nDirection = READ;
282 		else
283 			cmd.nDirection = WRITE;
284 	} else {
285 		cmd.nDirection = NO_DATA;
286 	}
287 
288 	if (scgp->debug > 0) {
289 		error("SEND(%d): cmd %02x, cdb = %d, data = %d, sense = %d\n",
290 			scgp->fd, cmd.nCommand[0], cmd.nCommandLength,
291 			cmd.nDataLength, cmd.nSenseLength);
292 	}
293 	ret = ioctl(scgp->fd, CD_PACKET_COMMAND, &cmd, sizeof (cmd));
294 	if (ret < 0)
295 		sp->ux_errno = geterrno();
296 
297 	if (ret < 0 && scgp->debug > 4) {
298 		js_fprintf((FILE *) scgp->errfile,
299 			"ioctl(CD_PACKET_COMMAND) ret: %d\n", ret);
300 	}
301 
302 	if (ret < 0 && cmd.nError) {
303 		sp->u_scb.cmd_scb[0] = ST_CHK_COND;
304 		if (scgp->debug > 0)
305 			error("result: scsi %02x\n", cmd.nError);
306 
307 		switch (cmd.nError) {
308 
309 		case SC_UNIT_ATTENTION:
310 		case SC_NOT_READY:
311 			sp->error = SCG_RETRYABLE;	/* may be BUS_BUSY */
312 			sp->u_scb.cmd_scb[0] |= ST_BUSY;
313 			break;
314 		case SC_ILLEGAL_REQUEST:
315 			break;
316 		default:
317 			break;
318 		}
319 	} else {
320 		sp->u_scb.cmd_scb[0] = 0x00;
321 	}
322 
323 	return (0);
324 }
325