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-osf.c 1.26 04/01/15 Copyright 1998 J. Schilling */
15 * Interface for Digital UNIX (OSF/1 generic SCSI implementation (/dev/cam).
17 * Created out of the hacks from:
18 * Stefan Traby <stefan@sime.com> and
19 * Bruno Achauer <bruno@tk.uni-linz.ac.at>
21 * Warning: you may change this source, but if you do that
22 * you need to change the _usal_version and _usal_auth* string below.
23 * You may not return "schily" for an SCG_AUTHOR request anymore.
24 * Choose your name instead of "schily" and make clear that the version
25 * string is related to a modified source.
27 * Copyright (c) 1998 J. Schilling
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License version 2
32 * as published by the Free Software Foundation.
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
39 * You should have received a copy of the GNU General Public License along with
40 * this program; see the file COPYING. If not, write to the Free Software
41 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #include <sys/types.h>
45 #include <io/common/iotypes.h>
46 #include <io/cam/cam.h>
47 #include <io/cam/uagt.h>
50 * Warning: you may change this source, but if you do that
51 * you need to change the _usal_version and _usal_auth* string below.
52 * You may not return "schily" for an SCG_AUTHOR request anymore.
53 * Choose your name instead of "schily" and make clear that the version
54 * string is related to a modified source.
56 static char _usal_trans_version[] = "scsi-osf.c-1.26"; /* The version for this transport*/
58 #define MAX_SCG 16 /* Max # of SCSI controllers */
63 int usalfile; /* Used for ioctl() */
64 short usalfiles[MAX_SCG][MAX_TGT][MAX_LUN];
66 #define usallocal(p) ((struct usal_local *)((p)->local))
68 static BOOL scsi_checktgt(SCSI *usalp, int f, int busno, int tgt, int tlun);
71 * I don't have any documentation about CAM
73 #define MAX_DMA_OSF_CAM (64*1024)
75 #ifndef AUTO_SENSE_LEN
76 # define AUTO_SENSE_LEN 32 /* SCG_MAX_SENSE */
80 * Return version information for the low level SCSI transport code.
81 * This has been introduced to make it easier to trace down problems
85 usalo_version(SCSI *usalp, int what)
87 if (usalp != (SCSI *)0) {
91 return (_usal_trans_version);
93 * If you changed this source, you are not allowed to
94 * return "schily" for the SCG_AUTHOR request.
97 return (_usal_auth_cdrkit);
106 usalo_help(SCSI *usalp, FILE *f)
108 __usal_help(f, "CAM", "Generic transport independent SCSI (Common Access Method)",
109 "", "bus,target,lun", "1,2,0", TRUE, FALSE);
114 usalo_open(SCSI *usalp, char *device)
116 int busno = usal_scsibus(usalp);
117 int tgt = usal_target(usalp);
118 int tlun = usal_lun(usalp);
123 if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
126 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
127 "Illegal value for busno, target or lun '%d,%d,%d'",
132 if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
135 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
136 "Open by 'devname' not supported on this OS");
140 if (usalp->local == NULL) {
141 usalp->local = malloc(sizeof (struct usal_local));
142 if (usalp->local == NULL)
144 usallocal(usalp)->usalfile = -1;
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 usallocal(usalp)->usalfiles[b][t][l] = 0;
154 if (usallocal(usalp)->usalfile != -1) /* multiple opens ??? */
155 return (1); /* not yet ready .... */
157 if ((usallocal(usalp)->usalfile = open("/dev/cam", O_RDWR, 0)) < 0) {
159 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
160 "Cannot open '/dev/cam'");
164 if (busno >= 0 && tgt >= 0 && tlun >= 0) {
165 /* scsi_checktgt() ??? */
166 for (l = 0; l < MAX_LUN; l++)
167 usallocal(usalp)->usalfiles[b][t][l] = 1;
171 * There seems to be no clean way to check whether
172 * a SCSI bus is present in the current system.
173 * scsi_checktgt() is used as a workaround for this problem.
175 for (b = 0; b < MAX_SCG; b++) {
176 for (t = 0; t < MAX_TGT; t++) {
177 if (scsi_checktgt(usalp, usallocal(usalp)->usalfile, b, t, 0)) {
178 for (l = 0; l < MAX_LUN; l++)
179 usallocal(usalp)->usalfiles[b][t][l] = 1;
181 * Found a target on this bus.
182 * Comment the 'break' for a complete scan.
192 usalo_close(SCSI *usalp)
194 if (usalp->local == NULL)
197 if (usallocal(usalp)->usalfile >= 0)
198 close(usallocal(usalp)->usalfile);
199 usallocal(usalp)->usalfile = -1;
204 * We send a test unit ready command to the target to check whether the
205 * OS is considering this target to be valid.
206 * XXX Is this really needed? We should rather let the cmd fail later.
209 scsi_checktgt(SCSI *usalp, int f, int busno, int tgt, int tlun)
211 struct usal_cmd *sp = usalp->scmd;
215 int obus = usal_scsibus(usalp);
216 int otgt = usal_target(usalp);
217 int olun = usal_lun(usalp);
219 usal_settarget(usalp, busno, tgt, tlun);
223 fillbytes((caddr_t)sp, sizeof (*sp), '\0');
224 sp->addr = (caddr_t)0;
226 sp->flags = SCG_DISRE_ENA | SCG_SILENT;
227 sp->cdb_len = SC_G0_CDBLEN;
228 sp->sense_len = CCS_SENSE_LEN;
229 sp->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY;
230 sp->cdb.g0_cdb.lun = usal_lun(usalp);
233 usal_settarget(usalp, obus, otgt, olun);
236 if (sp->error != SCG_FATAL)
238 ret = sp->ux_errno != EINVAL;
245 usalo_maxdma(SCSI *usalp, long amt)
247 long maxdma = MAX_DMA_OSF_CAM;
253 usalo_getbuf(SCSI *usalp, long amt)
255 if (usalp->debug > 0) {
256 fprintf((FILE *)usalp->errfile,
257 "usalo_getbuf: %ld bytes\n", amt);
259 usalp->bufbase = valloc((size_t)(amt));
260 return (usalp->bufbase);
264 usalo_freebuf(SCSI *usalp)
267 free(usalp->bufbase);
268 usalp->bufbase = NULL;
272 usalo_havebus(SCSI *usalp, int busno)
276 if (busno < 0 || busno >= MAX_SCG)
279 if (usalp->local == NULL)
282 for (t = 0; t < MAX_TGT; t++) {
283 if (usallocal(usalp)->usalfiles[busno][t][0] != 0)
291 usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
293 if (usalp->local == NULL)
296 return ((busno < 0 || busno >= MAX_SCG) ? -1 : usallocal(usalp)->usalfile);
300 usalo_initiator_id(SCSI *usalp)
306 usalo_isatapi(SCSI *usalp)
312 usalo_reset(SCSI *usalp, int what)
319 usalo_send(SCSI *usalp)
321 struct usal_cmd *sp = usalp->scmd;
330 sp->error = SCG_FATAL;
334 fillbytes(&ua, sizeof (UAGT_CAM_CCB), 0);
335 fillbytes(&ccb, sizeof (CCB_SCSIIO), 0);
337 ua.uagt_ccb = (CCB_HEADER *) &ccb;
338 ua.uagt_ccblen = sizeof (CCB_SCSIIO);
339 ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb;
340 ccb.cam_ch.cam_ccb_len = sizeof (CCB_SCSIIO);
342 ua.uagt_snsbuf = ccb.cam_sense_ptr = sp->u_sense.cmd_sense;
343 ua.uagt_snslen = ccb.cam_sense_len = AUTO_SENSE_LEN;
345 cdb = (unsigned char *) ccb.cam_cdb_io.cam_cdb_bytes;
347 ccb.cam_timeout = sp->timeout;
349 ccb.cam_data_ptr = ua.uagt_buffer = (Uchar *) sp->addr;
350 ccb.cam_dxfer_len = ua.uagt_buflen = sp->size;
351 ccb.cam_ch.cam_func_code = XPT_SCSI_IO;
352 ccb.cam_ch.cam_flags = 0; /* CAM_DIS_CALLBACK; */
355 ccb.cam_data_ptr = ua.uagt_buffer = (Uchar *) NULL;
356 ccb.cam_ch.cam_flags |= CAM_DIR_NONE;
358 if (sp->flags & SCG_RECV_DATA) {
359 ccb.cam_ch.cam_flags |= CAM_DIR_IN;
361 ccb.cam_ch.cam_flags |= CAM_DIR_OUT;
365 ccb.cam_cdb_len = sp->cdb_len;
366 for (i = 0; i < sp->cdb_len; i++)
367 cdb[i] = sp->cdb.cmd_cdb[i];
369 ccb.cam_ch.cam_path_id = usal_scsibus(usalp);
370 ccb.cam_ch.cam_target_id = usal_target(usalp);
371 ccb.cam_ch.cam_target_lun = usal_lun(usalp);
375 sp->error = SCG_NO_ERROR;
378 if (ioctl(usalp->fd, UAGT_CAM_IO, (caddr_t) &ua) < 0) {
379 sp->ux_errno = geterrno();
380 sp->error = SCG_FATAL;
381 if (usalp->debug > 0) {
382 errmsg("ioctl(fd, UAGT_CAM_IO, dev=%d,%d,%d) failed.\n",
383 usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
387 if (usalp->debug > 0) {
388 errmsgno(EX_BAD, "cam_status = 0x%.2X scsi_status = 0x%.2X dev=%d,%d,%d\n",
389 ccb.cam_ch.cam_status,
391 usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
394 switch (ccb.cam_ch.cam_status & CAM_STATUS_MASK) {
396 case CAM_REQ_CMP: break;
398 case CAM_SEL_TIMEOUT: sp->error = SCG_FATAL;
402 case CAM_CMD_TIMEOUT: sp->error = SCG_TIMEOUT;
406 default: sp->error = SCG_RETRYABLE;
411 sp->u_scb.cmd_scb[0] = ccb.cam_scsi_status;
413 if (ccb.cam_ch.cam_status & CAM_AUTOSNS_VALID) {
414 sp->sense_count = MIN(ccb.cam_sense_len - ccb.cam_sense_resid,
416 sp->sense_count = MIN(sp->sense_count, sp->sense_len);
417 if (sp->sense_len < 0)
420 sp->resid = ccb.cam_resid;
424 * this is perfectly wrong.
425 * But without this, we hang...
427 if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN) {
428 fillbytes(&relsim, sizeof (CCB_RELSIM), 0);
429 relsim.cam_ch.cam_ccb_len = sizeof (CCB_SCSIIO);
430 relsim.cam_ch.cam_func_code = XPT_REL_SIMQ;
431 relsim.cam_ch.cam_flags = CAM_DIR_IN | CAM_DIS_CALLBACK;
432 relsim.cam_ch.cam_path_id = usal_scsibus(usalp);
433 relsim.cam_ch.cam_target_id = usal_target(usalp);
434 relsim.cam_ch.cam_target_lun = usal_lun(usalp);
436 relua.uagt_ccb = (struct ccb_header *) & relsim; /* wrong cast */
437 relua.uagt_ccblen = sizeof (relsim);
438 relua.uagt_buffer = NULL;
439 relua.uagt_buflen = 0;
441 if (ioctl(usalp->fd, UAGT_CAM_IO, (caddr_t) & relua) < 0)
442 errmsg("DEC CAM -> LMA\n");