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