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 /* @(#)scsiopen.c 1.95 04/01/14 Copyright 1995,2000 J. Schilling */
15 * SCSI command functions for cdrecord
17 * Copyright (c) 1995,2000 J. Schilling
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License version 2
22 * as published by the Free Software Foundation.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License along with
30 * this program; see the file COPYING. If not, write to the Free Software
31 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 * NOTICE: The Philips CDD 521 has several firmware bugs.
36 * One of them is not to respond to a SCSI selection
37 * within 200ms if the general load on the
38 * SCSI bus is high. To deal with this problem
39 * most of the SCSI commands are send with the
40 * SCG_CMD_RETRY flag enabled.
42 * Note that the only legal place to assign
43 * values to usal_scsibus() usal_target() and usal_lun()
44 * is usal_settarget().
61 #include <usal/usalcmd.h>
62 #include <usal/scsidefs.h>
63 #include <usal/scsireg.h>
64 #include <usal/scsitransp.h>
66 #if defined(linux) || defined(__linux) || defined(__linux__)
67 extern BOOL check_linux_26();
70 #define strbeg(s1, s2) (strstr((s2), (s1)) == (s2))
74 SCSI *usal_open(char *scsidev, char *errs, int slen, int debug, int be_verbose);
75 int usal_help(FILE *f);
76 static int usal_scandev(char *devp, char *errs, int slen, int *busp,
77 int *tgtp, int *lunp);
78 int usal_close(SCSI * usalp);
80 void usal_settimeout(SCSI * usalp, int timeout);
82 SCSI *usal_smalloc(void);
83 void usal_sfree(SCSI *usalp);
91 * dev=target,lun / dev=scsibus,target,lun
93 * Needed on some systems:
94 * dev=devicename:target,lun / dev=devicename:scsibus,target,lun
96 * On systems that don't support SCSI Bus scanning this syntax helps:
97 * dev=devicename:@ / dev=devicename:@,lun
98 * or dev=devicename (undocumented)
100 * NOTE: As the 'lun' is part of the SCSI command descriptor block, it
101 * must always be known. If the OS cannot map it, it must be
102 * specified on command line.
105 usal_open(char *scsidev, char *errs, int slen, int debug, int be_verbose)
119 usalp = usal_smalloc();
122 snprintf(errs, slen, "No memory for SCSI structure");
125 usalp->debug = debug;
126 usalp->overbose = be_verbose;
128 if (scsidev != NULL && scsidev[0] != '\0') {
130 if ((strncmp(scsidev, "HELP", 4) == 0) ||
131 (strncmp(scsidev, "help", 4) == 0)) {
135 if (strncmp(scsidev, "REMOTE", 6) == 0) {
137 * REMOTE:user@host:scsidev or
138 * REMOTE(transp):user@host:scsidev
139 * e.g.: REMOTE(/usr/bin/ssh):user@host:scsidev
141 * We must send the complete device spec to the remote
142 * site to allow parsing on both sites.
144 strncpy(devname, scsidev, sizeof (devname)-1);
145 devname[sizeof (devname)-1] = '\0';
146 if (sdev[6] == '(' || sdev[6] == ':')
147 sdev = strchr(sdev, ':');
153 * This seems to be an illegal remote dev spec.
154 * Give it a chance with a standard parsing.
160 * Now try to go past user@host spec.
163 sdev = strchr(&sdev[1], ':');
165 sdev++; /* Device name follows ... */
170 if ((devp = strchr(sdev, ':')) == NULL) {
171 if (strchr(sdev, ',') == NULL) {
172 /* Notation form: 'devname' (undocumented) */
173 /* Forward complete name to usal__open() */
174 /* Fetch bus/tgt/lun values from OS */
175 /* We may come here too with 'USCSI' */
177 lun = -2; /* Lun must be known */
178 if (devname[0] == '\0') {
179 strncpy(devname, scsidev,
181 devname[sizeof (devname)-1] = '\0';
184 /* Basic notation form: 'bus,tgt,lun' */
188 /* Notation form: 'devname:bus,tgt,lun'/'devname:@' */
189 /* We may come here too with 'USCSI:' */
190 if (devname[0] == '\0') {
192 * Copy over the part before the ':'
195 if (x1 >= (int)sizeof (devname))
196 x1 = sizeof (devname)-1;
197 strncpy(devname, scsidev, x1);
201 /* Check for a notation in the form 'devname:@' */
202 if (devp[0] == '@') {
203 if (devp[1] == '\0') {
205 } else if (devp[1] == ',') {
206 if (*astoi(&devp[2], &lun) != '\0') {
210 "Invalid lun specifier '%s'",
217 * Got device:@ or device:@,lun
218 * Make sure not to call usal_scandev()
221 } else if (devp[0] == '\0') {
223 * Got USCSI: or ATAPI:
224 * Make sure not to call usal_scandev()
227 } else if (strchr(sdev, ',') == NULL) {
228 /* We may come here with 'ATAPI:/dev/hdc' */
229 strncpy(devname, scsidev,
231 devname[sizeof (devname)-1] = '\0';
233 lun = -2; /* Lun must be known */
235 * Make sure not to call usal_scandev()
243 /*fprintf(stderr, "10 scsidev '%s' sdev '%s' devp '%s' b: %d t: %d l: %d\n", scsidev, sdev, devp, bus, tgt, lun);*/
246 n = usal_scandev(devp, errs, slen, &bus, &tgt, &lun);
252 if (n >= 1 && n <= 3) { /* Got bus,target,lun or target,lun or tgt*/
253 usal_settarget(usalp, bus, tgt, lun);
254 } else if (n == -1) { /* Got device:@, fetch bus/lun from OS */
255 usal_settarget(usalp, -2, -2, lun);
256 } else if (devp != NULL) {
258 * XXX May this happen after we allow tgt to repesent tgt,0 ?
260 fprintf(stderr, "WARNING: device not valid, trying to use default target...\n");
261 usal_settarget(usalp, 0, 6, 0);
263 if (be_verbose && scsidev != NULL) {
264 fprintf(stderr, "scsidev: '%s'\n", scsidev);
265 if (devname[0] != '\0')
266 fprintf(stderr, "devname: '%s'\n", devname);
267 fprintf(stderr, "scsibus: %d target: %d lun: %d\n",
268 usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
271 fprintf(stderr, "usal__open(%s) %d,%d,%d\n",
273 usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
275 if (usal__open(usalp, devname) <= 0) {
276 if (errs && usalp->errstr)
277 snprintf(errs, slen, "%s", usalp->errstr);
289 usalp = usal_smalloc();
291 extern usal_ops_t usal_std_ops;
293 usalp->ops = &usal_std_ops;
295 printf("Supported SCSI transports for this platform:\n");
297 usal_remote()->usalo_help(usalp, f);
304 * Convert target,lun or scsibus,target,lun syntax.
305 * Check for bad syntax and invalid values.
306 * This is definitely better than using scanf() as it checks for syntax errors.
309 usal_scandev(char *devp, char *errs, int slen, int *busp, int *tgtp, int *lunp)
316 *busp = *tgtp = *lunp = 0;
325 snprintf(errs, slen, "Invalid bus or target specifier in '%s'", devp);
331 if (*p == ',' || *p == '\0') {
337 snprintf(errs, slen, "Invalid target or lun specifier in '%s'", devp);
347 snprintf(errs, slen, "Invalid lun specifier in '%s'", devp);
364 if (x1 < 0 || x2 < 0 || x3 < 0) {
366 snprintf(errs, slen, "Invalid value for bus, target or lun (%d,%d,%d)",
367 *busp, *tgtp, *lunp);
374 usal_close(SCSI *usalp)
381 char * usal_natname(SCSI *usalp, int busno, int tgt, int tlun) {
382 return usalp->ops->usalo_natname(usalp, busno, tgt, tlun);
385 int usal_fileno(SCSI *usalp, int busno, int tgt, int tlun) {
386 return usalp->ops->usalo_fileno(usalp, busno, tgt, tlun);
390 usal_settimeout(SCSI *usalp, int timeout)
394 usalp->deftimeout = timeout;
396 usalp->deftimeout = timeout;
404 extern usal_ops_t usal_dummy_ops;
406 usalp = (SCSI *)malloc(sizeof (*usalp));
410 fillbytes(usalp, sizeof (*usalp), 0);
411 usalp->ops = &usal_dummy_ops;
412 usal_settarget(usalp, -1, -1, -1);
414 usalp->deftimeout = 20;
415 usalp->running = FALSE;
417 usalp->cmdstart = (struct timeval *)malloc(sizeof (struct timeval));
418 if (usalp->cmdstart == NULL)
420 usalp->cmdstop = (struct timeval *)malloc(sizeof (struct timeval));
421 if (usalp->cmdstop == NULL)
423 usalp->scmd = (struct usal_cmd *)malloc(sizeof (struct usal_cmd));
424 if (usalp->scmd == NULL)
426 usalp->errstr = malloc(SCSI_ERRSTR_SIZE);
427 if (usalp->errstr == NULL)
429 usalp->errptr = usalp->errbeg = usalp->errstr;
430 usalp->errstr[0] = '\0';
431 usalp->errfile = (void *)stderr;
432 usalp->inq = (struct scsi_inquiry *)malloc(sizeof (struct scsi_inquiry));
433 if (usalp->inq == NULL)
435 usalp->cap = (struct scsi_capacity *)malloc(sizeof (struct scsi_capacity));
436 if (usalp->cap == NULL)
446 usal_sfree(SCSI *usalp)
449 free(usalp->cmdstart);
451 free(usalp->cmdstop);