1 /* @(#)scsi-bsd-os.c 1.28 04/01/15 Copyright 1997 J. Schilling */
2 #ifndef lint
3 static char __sccsid[] =
4 "@(#)scsi-bsd-os.c 1.28 04/01/15 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 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2, or (at your option)
24 * any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License along with
32 * this program; see the file COPYING. If not, write to the Free Software
33 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 */
35
36 #undef sense
37
38 #define scsi_sense bsdi_scsi_sense
39 #define scsi_inquiry bsdi_scsi_inquiry
40
41 /*
42 * Must use -I/sys...
43 * The next two files are in /sys/dev/scsi
44 */
45 #include <dev/scsi/scsi.h>
46 #include <dev/scsi/scsi_ioctl.h>
47
48 /*
49 * Warning: you may change this source, but if you do that
50 * you need to change the _scg_version and _scg_auth* string below.
51 * You may not return "schily" for an SCG_AUTHOR request anymore.
52 * Choose your name instead of "schily" and make clear that the version
53 * string is related to a modified source.
54 */
55 LOCAL char _scg_trans_version[] = "scsi-bsd-os.c-1.28"; /* The version for this transport*/
56
57 #define MAX_SCG 16 /* Max # of SCSI controllers */
58 #define MAX_TGT 16
59 #define MAX_LUN 8
60
61 struct scg_local {
62 short scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
63 };
64 #define scglocal(p) ((struct scg_local *)((p)->local))
65
66 #include <machine/param.h>
67
68 #define MAX_DMA_BSDI MAXPHYS /* More makes problems */
69
70
71 LOCAL BOOL scg_setup __PR((SCSI *scgp, int f, int busno, int tgt, int tlun));
72
73 /*
74 * Return version information for the low level SCSI transport code.
75 * This has been introduced to make it easier to trace down problems
76 * in applications.
77 */
78 LOCAL char *
scgo_version(scgp,what)79 scgo_version(scgp, what)
80 SCSI *scgp;
81 int what;
82 {
83 if (scgp != (SCSI *)0) {
84 switch (what) {
85
86 case SCG_VERSION:
87 return (_scg_trans_version);
88 /*
89 * If you changed this source, you are not allowed to
90 * return "schily" for the SCG_AUTHOR request.
91 */
92 case SCG_AUTHOR:
93 return (_scg_auth_schily);
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, "SCSIRAWCDB", "Generic SCSI for devices known by BSDi",
107 "", "devname:@,lun", "/dev/rsr0a:@,0", 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 busno = scg_scsibus(scgp);
117 int tgt = scg_target(scgp);
118 int tlun = scg_lun(scgp);
119 register int f;
120 register int b;
121 register int t;
122 register int l;
123 register int nopen = 0;
124 char devname[64];
125
126 if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
127 errno = EINVAL;
128 if (scgp->errstr)
129 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
130 "Illegal value for busno, target or lun '%d,%d,%d'",
131 busno, tgt, tlun);
132 return (-1);
133 }
134
135 if (scgp->local == NULL) {
136 scgp->local = malloc(sizeof (struct scg_local));
137 if (scgp->local == NULL)
138 return (0);
139
140 for (b = 0; b < MAX_SCG; b++) {
141 for (t = 0; t < MAX_TGT; t++) {
142 for (l = 0; l < MAX_LUN; l++)
143 scglocal(scgp)->scgfiles[b][t][l] = (short)-1;
144 }
145 }
146 }
147
148 if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2))
149 goto openbydev;
150
151 if (busno >= 0 && tgt >= 0 && tlun >= 0) {
152
153 js_snprintf(devname, sizeof (devname),
154 "/dev/su%d-%d-%d", busno, tgt, tlun);
155 f = open(devname, O_RDWR|O_NONBLOCK);
156 if (f < 0) {
157 goto openbydev;
158 }
159 scglocal(scgp)->scgfiles[busno][tgt][tlun] = f;
160 return (1);
161
162 } else for (b = 0; b < MAX_SCG; b++) {
163 for (t = 0; t < MAX_TGT; t++) {
164 for (l = 0; l < MAX_LUN; l++) {
165 js_snprintf(devname, sizeof (devname),
166 "/dev/su%d-%d-%d", b, t, l);
167 f = open(devname, O_RDWR|O_NONBLOCK);
168 /* error("open (%s) = %d\n", devname, f);*/
169
170 if (f < 0) {
171 if (errno != ENOENT &&
172 errno != ENXIO &&
173 errno != ENODEV) {
174 if (scgp->errstr)
175 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
176 "Cannot open '%s'",
177 devname);
178 return (0);
179 }
180 } else {
181 if (scg_setup(scgp, f, b, t, l))
182 nopen++;
183 }
184 }
185 }
186 }
187 /*
188 * Could not open /dev/su-* or got dev=devname:b,l,l / dev=devname:@,l
189 * We do the apropriate tests and try our best.
190 */
191 openbydev:
192 if (nopen == 0) {
193 if (device == NULL || device[0] == '\0')
194 return (0);
195 f = open(device, O_RDWR|O_NONBLOCK);
196 if (f < 0) {
197 if (scgp->errstr)
198 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
199 "Cannot open '%s'",
200 device);
201 return (0);
202 }
203 if (tlun == -2) { /* If 'lun' is not known, we reject */
204 close(f);
205 errno = EINVAL;
206 return (0);
207 }
208 busno = 0; /* use fake number, we cannot get it */
209 tgt = 0; /* use fake number, we cannot get it */
210 scg_settarget(scgp, busno, tgt, tlun);
211 /* 'lun' has been specified on command line */
212 if (scg_setup(scgp, f, busno, tgt, tlun))
213 nopen++;
214 }
215 return (nopen);
216 }
217
218 LOCAL int
scgo_close(scgp)219 scgo_close(scgp)
220 SCSI *scgp;
221 {
222 register int f;
223 register int b;
224 register int t;
225 register int l;
226
227 if (scgp->local == NULL)
228 return (-1);
229
230 for (b = 0; b < MAX_SCG; b++) {
231 for (t = 0; t < MAX_TGT; t++) {
232 for (l = 0; l < MAX_LUN; l++) {
233 f = scglocal(scgp)->scgfiles[b][t][l];
234 if (f >= 0)
235 close(f);
236 scglocal(scgp)->scgfiles[b][t][l] = (short)-1;
237 }
238 }
239 }
240 return (0);
241 }
242
243 LOCAL BOOL
scg_setup(scgp,f,busno,tgt,tlun)244 scg_setup(scgp, f, busno, tgt, tlun)
245 SCSI *scgp;
246 int f;
247 int busno;
248 int tgt;
249 int tlun;
250 {
251 int Bus;
252 int Target;
253 int Lun;
254 BOOL onetarget = FALSE;
255
256 if (scg_scsibus(scgp) >= 0 && scg_target(scgp) >= 0 && scg_lun(scgp) >= 0)
257 onetarget = TRUE;
258
259 /*
260 * Unfortunately there is no way to get the right values from kernel.
261 */
262 Bus = busno;
263 Target = tgt;
264 Lun = tlun;
265
266 if (scgp->debug > 0) {
267 js_fprintf((FILE *)scgp->errfile,
268 "Bus: %d Target: %d Lun: %d\n", Bus, Target, Lun);
269 }
270
271 if (Bus >= MAX_SCG || Target >= MAX_TGT || Lun >= MAX_LUN) {
272 close(f);
273 return (FALSE);
274 }
275
276 if (scglocal(scgp)->scgfiles[Bus][Target][Lun] == (short)-1)
277 scglocal(scgp)->scgfiles[Bus][Target][Lun] = (short)f;
278
279 if (onetarget) {
280 if (Bus == busno && Target == tgt && Lun == tlun) {
281 return (TRUE);
282 } else {
283 scglocal(scgp)->scgfiles[Bus][Target][Lun] = (short)-1;
284 close(f);
285 }
286 }
287 return (FALSE);
288 }
289
290 LOCAL long
scgo_maxdma(scgp,amt)291 scgo_maxdma(scgp, amt)
292 SCSI *scgp;
293 long amt;
294 {
295 long maxdma = MAX_DMA_BSDI;
296
297 return (maxdma);
298 }
299
300 LOCAL void *
scgo_getbuf(scgp,amt)301 scgo_getbuf(scgp, amt)
302 SCSI *scgp;
303 long amt;
304 {
305 if (scgp->debug > 0) {
306 js_fprintf((FILE *)scgp->errfile,
307 "scgo_getbuf: %ld bytes\n", amt);
308 }
309 scgp->bufbase = malloc((size_t)(amt));
310 return (scgp->bufbase);
311 }
312
313 LOCAL void
scgo_freebuf(scgp)314 scgo_freebuf(scgp)
315 SCSI *scgp;
316 {
317 if (scgp->bufbase)
318 free(scgp->bufbase);
319 scgp->bufbase = NULL;
320 }
321
322 LOCAL BOOL
scgo_havebus(scgp,busno)323 scgo_havebus(scgp, busno)
324 SCSI *scgp;
325 int busno;
326 {
327 register int t;
328 register int l;
329
330 if (busno < 0 || busno >= MAX_SCG)
331 return (FALSE);
332
333 if (scgp->local == NULL)
334 return (FALSE);
335
336 for (t = 0; t < MAX_TGT; t++) {
337 for (l = 0; l < MAX_LUN; l++)
338 if (scglocal(scgp)->scgfiles[busno][t][l] >= 0)
339 return (TRUE);
340 }
341 return (FALSE);
342 }
343
344 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)345 scgo_fileno(scgp, busno, tgt, tlun)
346 SCSI *scgp;
347 int busno;
348 int tgt;
349 int tlun;
350 {
351 if (busno < 0 || busno >= MAX_SCG ||
352 tgt < 0 || tgt >= MAX_TGT ||
353 tlun < 0 || tlun >= MAX_LUN)
354 return (-1);
355
356 if (scgp->local == NULL)
357 return (-1);
358
359 return ((int)scglocal(scgp)->scgfiles[busno][tgt][tlun]);
360 }
361
362 LOCAL int
scgo_initiator_id(scgp)363 scgo_initiator_id(scgp)
364 SCSI *scgp;
365 {
366 return (-1);
367 }
368
369 LOCAL int
scgo_isatapi(scgp)370 scgo_isatapi(scgp)
371 SCSI *scgp;
372 {
373 return (FALSE);
374 }
375
376 LOCAL int
scgo_reset(scgp,what)377 scgo_reset(scgp, what)
378 SCSI *scgp;
379 int what;
380 {
381 /*
382 * Cannot reset on BSD/OS
383 */
384 errno = EINVAL;
385 return (-1);
386 }
387
388 LOCAL int
scgo_send(scgp)389 scgo_send(scgp)
390 SCSI *scgp;
391 {
392 struct scg_cmd *sp = scgp->scmd;
393 scsi_user_cdb_t suc;
394 int ret = 0;
395
396 /* js_fprintf((FILE *)scgp->errfile, "f: %d\n", f);*/
397 if (scgp->fd < 0) {
398 sp->error = SCG_FATAL;
399 return (0);
400 }
401
402 /* Zero the structure... */
403 fillbytes(&suc, sizeof (suc), '\0');
404
405 /* Read or write? */
406 if (sp->flags & SCG_RECV_DATA) {
407 suc.suc_flags |= SUC_READ;
408 } else if (sp->size > 0) {
409 suc.suc_flags |= SUC_WRITE;
410 }
411
412 suc.suc_timeout = sp->timeout;
413
414 suc.suc_cdblen = sp->cdb_len;
415 movebytes(sp->cdb.cmd_cdb, suc.suc_cdb, suc.suc_cdblen);
416
417 suc.suc_datalen = sp->size;
418 suc.suc_data = sp->addr;
419
420 if (ioctl(scgp->fd, SCSIRAWCDB, &suc) < 0) {
421 ret = -1;
422 sp->ux_errno = geterrno();
423 if (sp->ux_errno != ENOTTY)
424 ret = 0;
425 } else {
426 sp->ux_errno = 0;
427 if (suc.suc_sus.sus_status != STS_GOOD)
428 sp->ux_errno = EIO;
429 }
430 fillbytes(&sp->scb, sizeof (sp->scb), '\0');
431 fillbytes(&sp->u_sense.cmd_sense, sizeof (sp->u_sense.cmd_sense), '\0');
432 #if 0
433 /*
434 * Unfortunalety, BSD/OS has no idea of DMA residual count.
435 */
436 sp->resid = req.datalen - req.datalen_used;
437 sp->sense_count = req.senselen_used;
438 #else
439 sp->resid = 0;
440 sp->sense_count = sizeof (suc.suc_sus.sus_sense);
441 #endif
442 if (sp->sense_count > SCG_MAX_SENSE)
443 sp->sense_count = SCG_MAX_SENSE;
444 movebytes(suc.suc_sus.sus_sense, sp->u_sense.cmd_sense, sp->sense_count);
445 sp->u_scb.cmd_scb[0] = suc.suc_sus.sus_status;
446
447 switch (suc.suc_sus.sus_status) {
448
449 case STS_GOOD:
450 sp->error = SCG_NO_ERROR; break;
451 case STS_CMD_TERMINATED:sp->error = SCG_TIMEOUT; break;
452 case STS_BUSY: sp->error = SCG_RETRYABLE; break;
453 case STS_CHECKCOND: sp->error = SCG_RETRYABLE; break;
454 case STS_QUEUE_FULL: sp->error = SCG_RETRYABLE; break;
455 default: sp->error = SCG_FATAL; break;
456 }
457
458 return (ret);
459 }
460
461 #define sense u_sense.Sense
462
463 #undef scsi_sense
464 #undef scsi_inquiry
465