1 /* @(#)scsi-next.c 1.33 06/11/26 Copyright 1997 J. Schilling */
2 #ifndef lint
3 static char __sccsid[] =
4 "@(#)scsi-next.c 1.33 06/11/26 Copyright 1997 J. Schilling";
5 #endif
6 /*
7 * Interface for the NeXT Step generic 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 #include <bsd/dev/scsireg.h>
43
44 /*
45 * Warning: you may change this source, but if you do that
46 * you need to change the _scg_version and _scg_auth* string below.
47 * You may not return "schily" for an SCG_AUTHOR request anymore.
48 * Choose your name instead of "schily" and make clear that the version
49 * string is related to a modified source.
50 */
51 LOCAL char _scg_trans_version[] = "scsi-next.c-1.33"; /* The version for this transport*/
52
53 #define MAX_SCG 16 /* Max # of SCSI controllers */
54 #define MAX_TGT 16
55 #define MAX_LUN 8
56
57 struct scg_local {
58 short scgfiles[MAX_SCG][MAX_TGT][MAX_LUN];
59 int scgfile;
60 int max_scsibus;
61 int cur_scsibus;
62 int cur_target;
63 int cur_lun;
64 };
65 #define scglocal(p) ((struct scg_local *)((p)->local))
66
67 /*#define MAX_DMA_NEXT (32*1024)*/
68 #define MAX_DMA_NEXT (64*1024) /* Check if this is not too big */
69
70
71 LOCAL BOOL scg_setup __PR((SCSI *scgp, int busno, int tgt, int tlun,
72 BOOL ex));
73
74 /*
75 * Return version information for the low level SCSI transport code.
76 * This has been introduced to make it easier to trace down problems
77 * in applications.
78 */
79 LOCAL char *
scgo_version(scgp,what)80 scgo_version(scgp, what)
81 SCSI *scgp;
82 int what;
83 {
84 if (scgp != (SCSI *)0) {
85 switch (what) {
86
87 case SCG_VERSION:
88 return (_scg_trans_version);
89 /*
90 * If you changed this source, you are not allowed to
91 * return "schily" for the SCG_AUTHOR request.
92 */
93 case SCG_AUTHOR:
94 return (_scg_auth_schily);
95 case SCG_SCCS_ID:
96 return (__sccsid);
97 }
98 }
99 return ((char *)0);
100 }
101
102 LOCAL int
scgo_help(scgp,f)103 scgo_help(scgp, f)
104 SCSI *scgp;
105 FILE *f;
106 {
107 __scg_help(f, "SGIOCREQ", "Generic SCSI",
108 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
109 return (0);
110 }
111
112 LOCAL int
scgo_open(scgp,device)113 scgo_open(scgp, device)
114 SCSI *scgp;
115 char *device;
116 {
117 int busno = scg_scsibus(scgp);
118 int tgt = scg_target(scgp);
119 int tlun = scg_lun(scgp);
120 register int f;
121 register int i;
122 char devname[64];
123
124 if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
125 errno = EINVAL;
126 if (scgp->errstr)
127 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
128 "Illegal value for busno, target or lun '%d,%d,%d'",
129 busno, tgt, tlun);
130 return (-1);
131 }
132
133 if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
134 errno = EINVAL;
135 if (scgp->errstr)
136 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
137 "Open by 'devname' not supported on this OS");
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 scglocal(scgp)->scgfile = -1;
147 scglocal(scgp)->max_scsibus = -1;
148 scglocal(scgp)->cur_scsibus = -1;
149 scglocal(scgp)->cur_target = -1;
150 scglocal(scgp)->cur_lun = -1;
151 }
152
153 for (i = 0; i < 4; i++) {
154 js_snprintf(devname, sizeof (devname), "/dev/sg%d", i);
155 f = open(devname, O_RDWR);
156 if (scgp->debug > 0)
157 errmsg("open(devname: '%s') : %d\n", devname, f);
158 if (f < 0)
159 continue;
160 scglocal(scgp)->scgfile = f;
161 break;
162
163 }
164 if (f >= 0) {
165 if (scglocal(scgp)->max_scsibus < 0) {
166 for (i = 0; i < MAX_SCG; i++) {
167 if (!SCGO_HAVEBUS(scgp, i))
168 break;
169 }
170 scglocal(scgp)->max_scsibus = i;
171 }
172 if (scgp->debug > 0) {
173 js_fprintf((FILE *)scgp->errfile,
174 "maxbus: %d\n", scglocal(scgp)->max_scsibus);
175 }
176 if (scglocal(scgp)->max_scsibus <= 0) {
177 scglocal(scgp)->max_scsibus = 1;
178 scglocal(scgp)->cur_scsibus = 0;
179 }
180
181 ioctl(f, SGIOCENAS);
182 if (busno > 0 && tgt > 0 && tlun > 0)
183 scg_setup(scgp, busno, tgt, tlun, TRUE);
184 return (1);
185 }
186 if (scgp->errstr)
187 js_snprintf(scgp->errstr, SCSI_ERRSTR_SIZE,
188 "Cannot open '/dev/sg*'");
189 return (0);
190 }
191
192 LOCAL int
scgo_close(scgp)193 scgo_close(scgp)
194 SCSI *scgp;
195 {
196 if (scgp->local == NULL)
197 return (-1);
198
199 if (scglocal(scgp)->scgfile >= 0)
200 close(scglocal(scgp)->scgfile);
201 scglocal(scgp)->scgfile = -1;
202 return (0);
203 }
204
205 LOCAL BOOL
scg_setup(scgp,busno,tgt,tlun,ex)206 scg_setup(scgp, busno, tgt, tlun, ex)
207 SCSI *scgp;
208 int busno;
209 int tgt;
210 int tlun;
211 BOOL ex;
212 {
213 scsi_adr_t sadr;
214
215 sadr.sa_target = tgt;
216 sadr.sa_lun = tlun;
217
218 if (scgp->debug > 0) {
219 js_fprintf((FILE *)scgp->errfile,
220 "scg_setup curbus %d -> %d\n", scglocal(scgp)->cur_scsibus, busno);
221 }
222
223 if (scgp->debug > 0 && ((scglocal(scgp)->cur_scsibus < 0 || scglocal(scgp)->cur_scsibus != busno)))
224 js_fprintf((FILE *)scgp->errfile, "setting SCSI bus to: %d\n", busno);
225 if ((scglocal(scgp)->cur_scsibus < 0 || scglocal(scgp)->cur_scsibus != busno) &&
226 ioctl(scglocal(scgp)->scgfile, SGIOCCNTR, &busno) < 0) {
227
228 scglocal(scgp)->cur_scsibus = -1; /* Driver is in undefined state */
229 if (ex)
230 /* comerr("Cannot set SCSI bus\n");*/
231 errmsg("Cannot set SCSI bus\n");
232 return (FALSE);
233 }
234 scglocal(scgp)->cur_scsibus = busno;
235
236 if (scgp->debug > 0) {
237 js_fprintf((FILE *)scgp->errfile,
238 "setting target/lun to: %d/%d\n", tgt, tlun);
239 }
240 if (ioctl(scglocal(scgp)->scgfile, SGIOCSTL, &sadr) < 0) {
241 if (ex)
242 comerr("Cannot set SCSI address\n");
243 return (FALSE);
244 }
245 scglocal(scgp)->cur_scsibus = busno;
246 scglocal(scgp)->cur_target = tgt;
247 scglocal(scgp)->cur_lun = tlun;
248 return (TRUE);
249 }
250
251 LOCAL long
scgo_maxdma(scgp,amt)252 scgo_maxdma(scgp, amt)
253 SCSI *scgp;
254 long amt;
255 {
256 long maxdma = MAX_DMA_NEXT;
257 #ifdef SGIOCMAXDMA
258 int m;
259
260 if (ioctl(scglocal(scgp)->scgfile, SGIOCMAXDMA, &m) >= 0) {
261 maxdma = m;
262 if (scgp->debug > 0) {
263 js_fprintf((FILE *)scgp->errfile,
264 "maxdma: %d\n", maxdma);
265 }
266 }
267 #endif
268 return (maxdma);
269 }
270 #ifdef XXX
271 #define SGIOCENAS _IO('s', 2) /* enable autosense */
272 #define SGIOCDAS _IO('s', 3) /* disable autosense */
273 #define SGIOCRST _IO('s', 4) /* reset SCSI bus */
274 #define SGIOCCNTR _IOW('s', 6, int) /* select controller */
275 #define SGIOCGAS _IOR('s', 7, int) /* get autosense */
276 #define SGIOCMAXDMA _IOR('s', 8, int) /* max DMA size */
277 #define SGIOCNUMTARGS _IOR('s', 9, int) /* # of targets/bus */
278 #endif
279
280 LOCAL void *
scgo_getbuf(scgp,amt)281 scgo_getbuf(scgp, amt)
282 SCSI *scgp;
283 long amt;
284 {
285 if (scgp->debug > 0) {
286 js_fprintf((FILE *)scgp->errfile,
287 "scgo_getbuf: %ld bytes\n", amt);
288 }
289 scgp->bufbase = valloc((size_t)(amt));
290 return (scgp->bufbase);
291 }
292
293 LOCAL void
scgo_freebuf(scgp)294 scgo_freebuf(scgp)
295 SCSI *scgp;
296 {
297 if (scgp->bufbase)
298 free(scgp->bufbase);
299 scgp->bufbase = NULL;
300 }
301
302 LOCAL int
scgo_numbus(scgp)303 scgo_numbus(scgp)
304 SCSI *scgp;
305 {
306 return (MAX_SCG);
307 }
308
309 LOCAL BOOL
scgo_havebus(scgp,busno)310 scgo_havebus(scgp, busno)
311 SCSI *scgp;
312 int busno;
313 {
314 if (busno < 0 || busno >= MAX_SCG)
315 return (FALSE);
316
317 if (scgp->local == NULL)
318 return (FALSE);
319
320 if (scglocal(scgp)->max_scsibus > 0 && busno >= scglocal(scgp)->max_scsibus)
321 return (FALSE);
322
323 return (scg_setup(scgp, busno, 0, 0, FALSE));
324 }
325
326 LOCAL int
scgo_fileno(scgp,busno,tgt,tlun)327 scgo_fileno(scgp, busno, tgt, tlun)
328 SCSI *scgp;
329 int busno;
330 int tgt;
331 int tlun;
332 {
333 if (busno < 0 || busno >= MAX_SCG ||
334 tgt < 0 || tgt >= MAX_TGT ||
335 tlun < 0 || tlun >= MAX_LUN)
336 return (-1);
337 if (scglocal(scgp)->max_scsibus > 0 && busno >= scglocal(scgp)->max_scsibus)
338 return (-1);
339
340 if (scgp->local == NULL)
341 return (-1);
342
343 if ((busno != scglocal(scgp)->cur_scsibus) || (tgt != scglocal(scgp)->cur_target) || (tlun != scglocal(scgp)->cur_lun)) {
344 if (!scg_setup(scgp, busno, tgt, tlun, FALSE))
345 return (-1);
346 }
347 return (scglocal(scgp)->scgfile);
348 }
349
350 LOCAL int
scgo_initiator_id(scgp)351 scgo_initiator_id(scgp)
352 SCSI *scgp;
353 {
354 return (-1);
355 }
356
357 LOCAL int
scgo_isatapi(scgp)358 scgo_isatapi(scgp)
359 SCSI *scgp;
360
361 {
362 return (FALSE);
363 }
364
365 LOCAL int
scgo_reset(scgp,what)366 scgo_reset(scgp, what)
367 SCSI *scgp;
368 int what;
369 {
370 if (what == SCG_RESET_NOP)
371 return (0);
372 if (what != SCG_RESET_BUS) {
373 errno = EINVAL;
374 return (-1);
375 }
376 return (ioctl(scgp->fd, SGIOCRST, 0));
377 }
378
379 LOCAL int
scgo_send(scgp)380 scgo_send(scgp)
381 SCSI *scgp;
382 {
383 struct scg_cmd *sp = scgp->scmd;
384 struct scsi_req req;
385 register long *lp1;
386 register long *lp2;
387 int ret = 0;
388
389 if (scgp->fd < 0 || (sp->cdb_len > sizeof (req.sr_cdb))) {
390 sp->error = SCG_FATAL;
391 sp->ux_errno = EIO;
392 return (0);
393 }
394 fillbytes(&req, sizeof (req), '\0');
395 movebytes(sp->cdb.cmd_cdb, &req.sr_cdb, sp->cdb_len);
396 if (sp->size) {
397 req.sr_dma_dir = SR_DMA_WR;
398 if (sp->flags & SCG_RECV_DATA)
399 req.sr_dma_dir = SR_DMA_RD;
400 }
401 req.sr_addr = sp->addr;
402 req.sr_dma_max = sp->size;
403 req.sr_ioto = sp->timeout;
404 if (ioctl(scgp->fd, SGIOCREQ, (void *)&req) < 0) {
405 ret = -1;
406 sp->ux_errno = geterrno();
407 if (sp->ux_errno != ENOTTY)
408 ret = 0;
409 } else {
410 sp->ux_errno = 0;
411 }
412 if (scgp->debug > 0) {
413 js_fprintf((FILE *)scgp->errfile, "dma_dir: %X\n", req.sr_dma_dir);
414 js_fprintf((FILE *)scgp->errfile, "dma_addr: %X\n", req.sr_addr);
415 js_fprintf((FILE *)scgp->errfile, "io_time: %d\n", req.sr_ioto);
416 js_fprintf((FILE *)scgp->errfile, "io_status: %d\n", req.sr_io_status);
417 js_fprintf((FILE *)scgp->errfile, "scsi_status: %X\n", req.sr_scsi_status);
418 js_fprintf((FILE *)scgp->errfile, "dma_xfer: %d\n", req.sr_dma_xfr);
419 }
420 sp->u_scb.cmd_scb[0] = req.sr_scsi_status;
421 sp->sense_count = sizeof (esense_reply_t);
422 if (sp->sense_count > sp->sense_len)
423 sp->sense_count = sp->sense_len;
424 if (sp->sense_count > SCG_MAX_SENSE)
425 sp->sense_count = SCG_MAX_SENSE;
426 if (sp->sense_count < 0)
427 sp->sense_count = 0;
428 movebytes(&req.sr_esense, sp->u_sense.cmd_sense, sp->sense_count);
429 sp->resid = sp->size - req.sr_dma_xfr;
430
431 switch (req.sr_io_status) {
432
433 case SR_IOST_GOOD: sp->error = SCG_NO_ERROR; break;
434
435 case SR_IOST_CHKSNV: sp->sense_count = 0;
436 case SR_IOST_CHKSV: sp->error = SCG_RETRYABLE;
437 break;
438
439 case SR_IOST_SELTO:
440 case SR_IOST_DMAOR:
441 sp->error = SCG_FATAL; break;
442
443 case SR_IOST_IOTO: sp->error = SCG_TIMEOUT; break;
444
445 case SR_IOST_PERM:
446 case SR_IOST_NOPEN:
447 sp->error = SCG_FATAL;
448 ret = (-1);
449 break;
450
451 default: sp->error = SCG_RETRYABLE; break;
452
453 }
454 return (ret);
455 }
456