2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)scsi-next.c 1.32 04/01/15 Copyright 1997 J. Schilling */
15 * Interface for the NeXT Step generic SCSI implementation.
17 * This is a hack, that tries to emulate the functionality
20 * Warning: you may change this source, but if you do that
21 * you need to change the _usal_version and _usal_auth* string below.
22 * You may not return "schily" for an SCG_AUTHOR request anymore.
23 * Choose your name instead of "schily" and make clear that the version
24 * string is related to a modified source.
26 * Copyright (c) 1997 J. Schilling
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License version 2
31 * as published by the Free Software Foundation.
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
38 * You should have received a copy of the GNU General Public License along with
39 * this program; see the file COPYING. If not, write to the Free Software
40 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #include <bsd/dev/scsireg.h>
46 * Warning: you may change this source, but if you do that
47 * you need to change the _usal_version and _usal_auth* string below.
48 * You may not return "schily" for an SCG_AUTHOR request anymore.
49 * Choose your name instead of "schily" and make clear that the version
50 * string is related to a modified source.
52 static char _usal_trans_version[] = "scsi-next.c-1.32"; /* The version for this transport*/
54 #define MAX_SCG 16 /* Max # of SCSI controllers */
59 short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
66 #define usallocal(p) ((struct usal_local *)((p)->local))
68 /*#define MAX_DMA_NEXT (32*1024)*/
69 #define MAX_DMA_NEXT (64*1024) /* Check if this is not too big */
72 static BOOL usal_setup(SCSI *usalp, int busno, int tgt, int tlun, BOOL ex);
75 * Return version information for the low level SCSI transport code.
76 * This has been introduced to make it easier to trace down problems
80 usalo_version(SCSI *usalp, int what)
82 if (usalp != (SCSI *)0) {
86 return (_usal_trans_version);
88 * If you changed this source, you are not allowed to
89 * return "schily" for the SCG_AUTHOR request.
92 return (_usal_auth_cdrkit);
101 usalo_help(SCSI *usalp, FILE *f)
103 __usal_help(f, "SGIOCREQ", "Generic SCSI",
104 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
109 usalo_open(SCSI *usalp, char *device)
111 int busno = usal_scsibus(usalp);
112 int tgt = usal_target(usalp);
113 int tlun = usal_lun(usalp);
118 if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
121 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
122 "Illegal value for busno, target or lun '%d,%d,%d'",
127 if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
130 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
131 "Open by 'devname' not supported on this OS");
135 if (usalp->local == NULL) {
136 usalp->local = malloc(sizeof (struct usal_local));
137 if (usalp->local == NULL)
140 usallocal(usalp)->usalfile = -1;
141 usallocal(usalp)->max_scsibus = -1;
142 usallocal(usalp)->cur_scsibus = -1;
143 usallocal(usalp)->cur_target = -1;
144 usallocal(usalp)->cur_lun = -1;
147 for (i = 0; i < 4; i++) {
148 snprintf(devname, sizeof (devname), "/dev/sg%d", i);
149 f = open(devname, O_RDWR);
150 if (usalp->debug > 0)
151 errmsg("open(devname: '%s') : %d\n", devname, f);
154 usallocal(usalp)->usalfile = f;
159 if (usallocal(usalp)->max_scsibus < 0) {
160 for (i = 0; i < MAX_SCG; i++) {
161 if (!SCGO_HAVEBUS(usalp, i))
164 usallocal(usalp)->max_scsibus = i;
166 if (usalp->debug > 0) {
167 fprintf((FILE *)usalp->errfile,
168 "maxbus: %d\n", usallocal(usalp)->max_scsibus);
170 if (usallocal(usalp)->max_scsibus <= 0) {
171 usallocal(usalp)->max_scsibus = 1;
172 usallocal(usalp)->cur_scsibus = 0;
176 if (busno > 0 && tgt > 0 && tlun > 0)
177 usal_setup(usalp, busno, tgt, tlun, TRUE);
181 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
182 "Cannot open '/dev/sg*'");
187 usalo_close(SCSI *usalp)
189 if (usalp->local == NULL)
192 if (usallocal(usalp)->usalfile >= 0)
193 close(usallocal(usalp)->usalfile);
194 usallocal(usalp)->usalfile = -1;
199 usal_setup(SCSI *usalp, int busno, int tgt, int tlun, BOOL ex)
203 sadr.sa_target = tgt;
206 if (usalp->debug > 0) {
207 fprintf((FILE *)usalp->errfile,
208 "usal_setup curbus %d -> %d\n", usallocal(usalp)->cur_scsibus, busno);
211 if (usalp->debug > 0 && ((usallocal(usalp)->cur_scsibus < 0 || usallocal(usalp)->cur_scsibus != busno)))
212 fprintf((FILE *)usalp->errfile, "setting SCSI bus to: %d\n", busno);
213 if ((usallocal(usalp)->cur_scsibus < 0 || usallocal(usalp)->cur_scsibus != busno) &&
214 ioctl(usallocal(usalp)->usalfile, SGIOCCNTR, &busno) < 0) {
216 usallocal(usalp)->cur_scsibus = -1; /* Driver is in undefined state */
218 /* comerr("Cannot set SCSI bus\n");*/
219 errmsg("Cannot set SCSI bus\n");
222 usallocal(usalp)->cur_scsibus = busno;
224 if (usalp->debug > 0) {
225 fprintf((FILE *)usalp->errfile,
226 "setting target/lun to: %d/%d\n", tgt, tlun);
228 if (ioctl(usallocal(usalp)->usalfile, SGIOCSTL, &sadr) < 0) {
230 comerr("Cannot set SCSI address\n");
233 usallocal(usalp)->cur_scsibus = busno;
234 usallocal(usalp)->cur_target = tgt;
235 usallocal(usalp)->cur_lun = tlun;
240 usalo_maxdma(SCSI *usalp, long amt)
242 long maxdma = MAX_DMA_NEXT;
246 if (ioctl(usallocal(usalp)->usalfile, SGIOCMAXDMA, &m) >= 0) {
248 if (usalp->debug > 0) {
249 fprintf((FILE *)usalp->errfile,
250 "maxdma: %d\n", maxdma);
257 #define SGIOCENAS _IO('s', 2) /* enable autosense */
258 #define SGIOCDAS _IO('s', 3) /* disable autosense */
259 #define SGIOCRST _IO('s', 4) /* reset SCSI bus */
260 #define SGIOCCNTR _IOW('s', 6, int) /* select controller */
261 #define SGIOCGAS _IOR('s', 7, int) /* get autosense */
262 #define SGIOCMAXDMA _IOR('s', 8, int) /* max DMA size */
263 #define SGIOCNUMTARGS _IOR('s', 9, int) /* # of targets/bus */
267 usalo_getbuf(SCSI *usalp, long amt)
269 if (usalp->debug > 0) {
270 fprintf((FILE *)usalp->errfile,
271 "usalo_getbuf: %ld bytes\n", amt);
273 usalp->bufbase = valloc((size_t)(amt));
274 return (usalp->bufbase);
278 usalo_freebuf(SCSI *usalp)
281 free(usalp->bufbase);
282 usalp->bufbase = NULL;
286 usalo_havebus(SCSI *usalp, int busno)
288 if (busno < 0 || busno >= MAX_SCG)
291 if (usalp->local == NULL)
294 if (usallocal(usalp)->max_scsibus > 0 && busno >= usallocal(usalp)->max_scsibus)
297 return (usal_setup(usalp, busno, 0, 0, FALSE));
301 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
303 if (busno < 0 || busno >= MAX_SCG ||
304 tgt < 0 || tgt >= MAX_TGT ||
305 tlun < 0 || tlun >= MAX_LUN)
307 if (usallocal(usalp)->max_scsibus > 0 && busno >= usallocal(usalp)->max_scsibus)
310 if (usalp->local == NULL)
313 if ((busno != usallocal(usalp)->cur_scsibus) || (tgt != usallocal(usalp)->cur_target) || (tlun != usallocal(usalp)->cur_lun)) {
314 if (!usal_setup(usalp, busno, tgt, tlun, FALSE))
317 return (usallocal(usalp)->usalfile);
321 usalo_initiator_id(SCSI *usalp)
327 usalo_isatapi(SCSI *usalp)
333 usalo_reset(SCSI *usalp, int what)
335 if (what == SCG_RESET_NOP)
337 if (what != SCG_RESET_BUS) {
341 return (ioctl(usalp->fd, SGIOCRST, 0));
345 usalo_send(SCSI *usalp)
347 struct usal_cmd *sp = usalp->scmd;
353 if (usalp->fd < 0 || (sp->cdb_len > sizeof (req.sr_cdb))) {
354 sp->error = SCG_FATAL;
358 fillbytes(&req, sizeof (req), '\0');
359 movebytes(sp->cdb.cmd_cdb, &req.sr_cdb, sp->cdb_len);
361 req.sr_dma_dir = SR_DMA_WR;
362 if (sp->flags & SCG_RECV_DATA)
363 req.sr_dma_dir = SR_DMA_RD;
365 req.sr_addr = sp->addr;
366 req.sr_dma_max = sp->size;
367 req.sr_ioto = sp->timeout;
368 if (ioctl(usalp->fd, SGIOCREQ, (void *)&req) < 0) {
370 sp->ux_errno = geterrno();
371 if (sp->ux_errno != ENOTTY)
376 if (usalp->debug > 0) {
377 fprintf((FILE *)usalp->errfile, "dma_dir: %X\n", req.sr_dma_dir);
378 fprintf((FILE *)usalp->errfile, "dma_addr: %X\n", req.sr_addr);
379 fprintf((FILE *)usalp->errfile, "io_time: %d\n", req.sr_ioto);
380 fprintf((FILE *)usalp->errfile, "io_status: %d\n", req.sr_io_status);
381 fprintf((FILE *)usalp->errfile, "scsi_status: %X\n", req.sr_scsi_status);
382 fprintf((FILE *)usalp->errfile, "dma_xfer: %d\n", req.sr_dma_xfr);
384 sp->u_scb.cmd_scb[0] = req.sr_scsi_status;
385 sp->sense_count = sizeof (esense_reply_t);
386 if (sp->sense_count > sp->sense_len)
387 sp->sense_count = sp->sense_len;
388 if (sp->sense_count > SCG_MAX_SENSE)
389 sp->sense_count = SCG_MAX_SENSE;
390 if (sp->sense_count < 0)
392 movebytes(&req.sr_esense, sp->u_sense.cmd_sense, sp->sense_count);
393 sp->resid = sp->size - req.sr_dma_xfr;
395 switch (req.sr_io_status) {
397 case SR_IOST_GOOD: sp->error = SCG_NO_ERROR; break;
399 case SR_IOST_CHKSNV: sp->sense_count = 0;
400 case SR_IOST_CHKSV: sp->error = SCG_RETRYABLE;
405 sp->error = SCG_FATAL; break;
407 case SR_IOST_IOTO: sp->error = SCG_TIMEOUT; break;
411 sp->error = SCG_FATAL;
415 default: sp->error = SCG_RETRYABLE; break;