Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libusal / scsi-linux-ata.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)scsi-linux-ata.c 1.7 04/06/12 Copyright 2002 J. Schilling */
14 /*
15  *      Interface for Linux generic SCSI implementation (sg).
16  *
17  *      This is the interface for the broken Linux SCSI generic driver.
18  *      This is a hack, that tries to emulate the functionality
19  *      of the usal driver.
20  *
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.
26  *
27  *      Copyright (c) 2002 J. Schilling
28  *
29  *      Thanks to Alexander Kern <alex.kern@gmx.de> for the idea and first
30  *      code fragments for supporting the CDROM_SEND_PACKET ioctl() from
31  *      the cdrom.c kernel driver. Please note that this interface in priciple
32  *      is completely unneeded but the Linux kernel is just a cluster of
33  *      code and does not support planned orthogonal interface systems.
34  *      For this reason we need CDROM_SEND_PACKET in order to work around a
35  *      bug in the linux kernel that prevents to use PCATA drives because
36  *      the kernel panics if you try to put ide-scsi on top of the PCATA
37  *      driver.
38  */
39 /*
40  * This program is free software; you can redistribute it and/or modify
41  * it under the terms of the GNU General Public License version 2
42  * as published by the Free Software Foundation.
43  *
44  * This program is distributed in the hope that it will be useful,
45  * but WITHOUT ANY WARRANTY; without even the implied warranty of
46  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47  * GNU General Public License for more details.
48  *
49  * You should have received a copy of the GNU General Public License along with
50  * this program; see the file COPYING.  If not, write to the Free Software
51  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
52  */
53
54 #ifdef  USE_OLD_ATAPI
55
56 #define ata_sccsid "obsolete ATAPI driver in cdrkit"
57
58 static  char    _usal_atrans_version[] = "scsi-linux-ata.c-1.7";        /* The version for ATAPI transport*/
59
60 static  char *usalo_aversion(SCSI *usalp, int what);
61 static  int     usalo_ahelp(SCSI *usalp, FILE *f);
62 static  int     usalo_aopen(SCSI *usalp, char *device);
63 static  int     usalo_aclose(SCSI *usalp);
64 static  long    usalo_amaxdma(SCSI *usalp, long amt);
65 static  BOOL    usalo_ahavebus(SCSI *usalp, int);
66 static  int     usalo_afileno(SCSI *usalp, int, int, int);
67 static  int     usalo_ainitiator_id(SCSI *usalp);
68 static  int     usalo_aisatapi(SCSI *usalp);
69 static  int     usalo_areset(SCSI *usalp, int what);
70 static  int     usalo_asend(SCSI *usalp);
71
72 static usal_ops_t ata_ops = {
73         usalo_asend,
74         usalo_aversion,
75         usalo_ahelp,
76         usalo_aopen,
77         usalo_aclose,
78         usalo_amaxdma,
79         usalo_getbuf,           /* Shared with SG driver */
80         usalo_freebuf,          /* Shared with SG driver */
81         usalo_ahavebus,
82         usalo_afileno,
83         usalo_ainitiator_id,
84         usalo_aisatapi,
85         usalo_areset,
86 };
87
88 #define HOST_EMPTY      0xF
89 #define HOST_SCSI       0x0
90 #define HOST_IDE        0x1
91 #define HOST_USB        0x2
92 #define HOST_IEEE1389   0x3
93 #define HOST_PARALLEL   0x4
94 #define HOST_OTHER      0xE
95
96
97 #define typlocal(p, schillybus)         usallocal(p)->bc[schillybus].typ
98 #define buslocal(p, schillybus)         usallocal(p)->bc[schillybus].bus
99 #define hostlocal(p, schillybus)        usallocal(p)->bc[schillybus].host
100
101 #define MAX_DMA_ATA (131072-1)  /* EINVAL (hart) ENOMEM (weich) bei mehr ... */
102                                 /* Bei fehlerhaftem Sense Pointer kommt EFAULT */
103
104 static int usalo_send(SCSI * usalp);
105 static BOOL sg_amapdev(SCSI * usalp, int f, char *device, int *bus, 
106                                                           int *target, int *lun);
107 static BOOL sg_amapdev_scsi(SCSI * usalp, int f, int *busp, int *tgtp,
108                                                                          int *lunp, int *chanp, int *inop);
109 static int usalo_aget_first_free_shillybus(SCSI * usalp, int subsystem,
110                                                                                                                 int host, int bus);
111 static int usalo_amerge(char *path, char *readedlink, char *buffer, int buflen);
112
113 /*
114  * uncomment this when you will get a debug file #define DEBUG
115  */
116 #ifdef DEBUG
117 #define LOGFILE "scsi-linux-ata.log"
118 #define log(a)  sglog a
119
120 static  void    sglog(const char *fmt, ...);
121
122 #include <vadefs.h>
123
124 /* VARARGS1 */
125 static void
126 sglog(const char *fmt, ...)
127 {
128         va_list args;
129         FILE    *f       = fopen(LOGFILE, "a");
130
131         if (f == NULL)
132                 return;
133
134         va_start(args, fmt);
135         vfprintf(f, fmt, args);
136         va_end(args);
137         fclose(f);
138 }
139 #else
140 #define log(a)
141 #endif  /* DEBUG */
142
143 static  int     scan_internal(SCSI * usalp, int *fatal);
144
145 /*
146  * Return version information for the low level SCSI transport code.
147  * This has been introduced to make it easier to trace down problems
148  * in applications.
149  */
150 static char *
151 usalo_aversion(SCSI *usalp, int what)
152 {
153         if (usalp != (SCSI *)0) {
154                 switch (what) {
155
156                 case SCG_VERSION:
157                         return (_usal_atrans_version);
158                 /*
159                  * If you changed this source, you are not allowed to
160                  * return "schily" for the SCG_AUTHOR request.
161                  */
162                 case SCG_AUTHOR:
163                         return (_usal_auth_cdrkit);
164                 case SCG_SCCS_ID:
165                         return (ata_sccsid);
166                 }
167         }
168         return ((char *)0);
169 }
170
171 static int
172 usalo_ahelp(SCSI *usalp, FILE *f)
173 {
174         __usal_help(f, "ATA", "ATA Packet specific SCSI transport",
175                 "ATAPI:", "bus,target,lun", "ATAPI:1,2,0", TRUE, FALSE);
176         return (0);
177 }
178
179 static int
180 usalo_aopen(SCSI *usalp, char *device)
181 {
182         int     bus = usal_scsibus(usalp);
183         int     target = usal_target(usalp);
184         int     lun = usal_lun(usalp);
185
186         register int    f;
187         register int    b;
188         register int    t;
189         register int    l;
190                 int     nopen = 0;
191
192         if (usalp->overbose)
193                 fprintf(stderr, "Warning: Using ATA Packet interface.\n");
194         if (usalp->overbose) {
195                 fprintf(stderr, "Warning: The related Linux kernel interface code seems to be unmaintained.\n");
196                 fprintf(stderr, "Warning: There is absolutely NO DMA, operations thus are slow.\n");
197         }
198
199         log(("\n<<<<<<<<<<<<<<<<  LOGGING ON >>>>>>>>>>>>>>>>>\n"));
200         if (bus >= MAX_SCHILLY_HOSTS || target >= MAX_TGT || lun >= MAX_LUN) {
201                 errno = EINVAL;
202                 if (usalp->errstr)
203                         snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
204                                 "Illegal value for bus, target or lun '%d,%d,%d'",
205                                 bus, target, lun);
206
207                 return (-1);
208         }
209
210         if (usalp->local == NULL) {
211                 usalp->local = malloc(sizeof (struct usal_local));
212                 if (usalp->local == NULL) {
213                         return (0);
214                 }
215
216                 usallocal(usalp)->usalfile = -1;
217                 usallocal(usalp)->pgbus = -2;
218                 usallocal(usalp)->SCSIbuf = (char *)-1;
219                 usallocal(usalp)->pack_id = 5;
220                 usallocal(usalp)->drvers = -1;
221                 usallocal(usalp)->isold = -1;
222                 usallocal(usalp)->xbufsize = 0L;
223                 usallocal(usalp)->xbuf = NULL;
224
225
226                 for (b = 0; b < MAX_SCHILLY_HOSTS; b++) {
227                         typlocal(usalp, b) = HOST_EMPTY;
228                         for (t = 0; t < MAX_TGT; t++) {
229                                 for (l = 0; l < MAX_LUN; l++)
230                                         usallocal(usalp)->usalfiles[b][t][l] = (short) -1;
231                         }
232                 }
233         }
234
235         if (device != NULL && strcmp(device, "ATAPI") == 0)
236                 goto atascan;
237
238         /* if not scanning */
239         if ((device != NULL && *device != '\0') || (bus == -2 && target == -2))
240                 goto openbydev;
241
242 atascan:
243         if (scan_internal(usalp, &nopen)) {
244                 if (usalp->errstr)
245                         printf(usalp->errstr, "INFO: scan_internal(...) failed");
246                 return (-1);
247         }
248         return (nopen);
249
250 openbydev:
251         if (device != NULL && strncmp(device, "ATAPI:", 6) == 0)
252                 device += 6;
253         if (usalp->debug > 3) {
254                 fprintf((FILE *) usalp->errfile, "INFO: do usalo_open openbydev");
255         }
256         if (device != NULL && *device != '\0') {
257                 int     schilly_bus,
258                         starget,
259                         slun;
260
261                 f = sg_open_excl(device, O_RDONLY | O_NONBLOCK, FALSE);
262
263                 if (f < 0) {
264                         if (usalp->errstr)
265                                 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
266                                         "Cannot open '%s'", device);
267                         return (0);
268                 }
269                 if (sg_amapdev(usalp, f, device, &schilly_bus, &starget, &slun)) {
270                         usal_settarget(usalp, schilly_bus, starget, slun);
271                         return (++nopen);
272                 }
273         }
274         return (nopen);
275 }
276
277 static int
278 scan_internal(SCSI *usalp, int *nopen)
279 {
280         int     i,
281                 f;
282         int     schilly_bus,
283                 target,
284                 lun;
285         char    device[128];
286         /*
287          * try always with devfs
288          * unfortunatelly the solution with test of existing
289          * of '/dev/.devfsd' don't work, because it root.root 700
290          * and i don't like run suid root
291          */
292         BOOL    DEVFS = TRUE;
293
294         if (DEVFS) {
295                 for (i = 0; ; i++) {
296                         sprintf(device, "/dev/cdroms/cdrom%i", i);
297                         if ((f = open(device, O_RDONLY | O_NONBLOCK)) < 0) {
298                                 if (errno != ENOENT && errno != ENXIO && errno != ENODEV && errno != EACCES) {
299                                         if (usalp->debug > 4) {
300                                                 fprintf((FILE *) usalp->errfile,
301                                                 "try open(%s) return %i, errno %i, cancel\n", device, f, errno);
302                                         }
303                                         return (-2);
304                                 } else if (errno == ENOENT || errno == ENODEV) {
305                                         if (usalp->debug > 4) {
306                                                 fprintf((FILE *) usalp->errfile,
307                                                 "try open(%s) return %i, errno %i\n", device, f, errno);
308                                         }
309                                         if (0 == i) {
310                                                 DEVFS = FALSE;
311                                                 if (usalp->debug > 4) {
312                                                         fprintf((FILE *) usalp->errfile,
313                                                         "DEVFS not detected, continuing with old dev\n");
314                                                 }
315                                         }
316                                         break;
317                                 }
318                                 if (usalp->debug > 4) {
319                                         if (errno == EACCES) {
320                                                 fprintf((FILE *) usalp->errfile,
321                                                 "errno (EACCESS), you don't have the needed rights for %s\n",
322                                                 device);
323                                         }
324                                         fprintf((FILE *) usalp->errfile,
325                                         "try open(%s) return %i, errno %i, trying next cdrom\n",
326                                         device, f, errno);
327                                 }
328                         } else {
329                                 if (usalp->debug > 4) {
330                                         fprintf((FILE *) usalp->errfile,
331                                         "try open(%s) return %i errno %i calling sg_mapdev(...)\n",
332                                         device, f, errno);
333                                 }
334                                 if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) {
335                                         (++(*nopen));
336                                 } else {
337                                         close(f);
338                                 }
339                         }
340                 }
341         }
342         if (!DEVFS) {
343                 /* for /dev/sr0 - /dev/sr? */
344                 for (i = 0; i<16 ; i++) {
345                         sprintf(device, "/dev/sr%i", i);
346                         if ((f = open(device, O_RDONLY | O_NONBLOCK)) < 0) {
347                                 if (errno != ENOENT && errno != ENXIO && errno != ENODEV && errno != EACCES) {
348                                         if (usalp->debug > 4) {
349                                                 fprintf((FILE *) usalp->errfile,
350                                                 "try open(%s) return %i, errno %i, cancel\n",
351                                                 device, f, errno);
352                                         }
353                                         return (-2);
354         }
355                         } else {
356                                 if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) {
357                                         (++(*nopen));
358                                 } else {
359                                         close(f);
360                                 }
361                         }
362                 }
363
364                 /* for /dev/hda - /dev/hdz */
365                 for (i = 'a'; i <= 'z'; i++) {
366                         sprintf(device, "/dev/hd%c", i);
367                         if ((f = open(device, O_RDONLY | O_NONBLOCK)) < 0) {
368                                 if (errno != ENOENT && errno != ENXIO && errno != EACCES) {
369                                         if (usalp->debug > 4) {
370                                                 fprintf((FILE *) usalp->errfile,
371                                                 "try open(%s) return %i, errno %i, cancel\n",
372                                                 device, f, errno);
373                                         }
374                                         return (-2);
375         }
376                         } else {
377                                 /* ugly hack, make better, when you can. Alex */
378                                 if (0 > ioctl(f, CDROM_DRIVE_STATUS, CDSL_CURRENT)) {
379                                         if (usalp->debug > 4) {
380                                                 fprintf((FILE *) usalp->errfile,
381                                                 "%s is not a cdrom, skipping\n",
382                                                 device);
383                                         }
384                                         close(f);
385                                 } else if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) {
386                                         (++(*nopen));
387                                 } else {
388                                         close(f);
389                                 }
390                         }
391                 }
392         }
393         return (0);
394 }
395
396 static int
397 usalo_aclose(SCSI *usalp)
398 {
399         register int    f;
400         register int    h;
401         register int    t;
402         register int    l;
403
404         if (usalp->local == NULL)
405                 return (-1);
406
407         for (h = 0; h < MAX_SCHILLY_HOSTS; h++) {
408                 typlocal(usalp, h) = (HOST_EMPTY);
409                 for (t = 0; t < MAX_TGT; t++) {
410                         for (l = 0; l < MAX_LUN; l++) {
411                                 f = usallocal(usalp)->usalfiles[h][t][l];
412                                 if (f >= 0)
413                                         close(f);
414                                 usallocal(usalp)->usalfiles[h][t][l] = (short) -1;
415                         }
416                 }
417         }
418
419         if (usallocal(usalp)->xbuf != NULL) {
420                 free(usallocal(usalp)->xbuf);
421                 usallocal(usalp)->xbufsize = 0L;
422                 usallocal(usalp)->xbuf = NULL;
423         }
424         log(("<<<<<<<<<<<<<<<<  LOGGING OFF >>>>>>>>>>>>>>>>>\n\n"));
425         return (0);
426 }
427
428 static int
429 usalo_aget_first_free_shillybus(SCSI *usalp, int subsystem, int host, int bus)
430 {
431         int     first_free_schilly_bus;
432
433         for (first_free_schilly_bus = 0;
434                         first_free_schilly_bus < MAX_SCHILLY_HOSTS;
435                                                 first_free_schilly_bus++) {
436
437                 if (typlocal(usalp, first_free_schilly_bus) == HOST_EMPTY ||
438                     (typlocal(usalp, first_free_schilly_bus) == subsystem &&
439                     hostlocal(usalp, first_free_schilly_bus) == host &&
440                     buslocal(usalp, first_free_schilly_bus) == bus))
441                         break;
442         }
443
444         if (first_free_schilly_bus >= MAX_SCHILLY_HOSTS) {
445                 errmsgno(EX_BAD, "ERROR: in usalo_get_first_free_shillybus(...). Too many CDROMs, more than %i",
446                         MAX_SCHILLY_HOSTS);
447                 errmsgno(EX_BAD, "Increase MAX_SCHILLY_HOSTS in scsi-linux-ata.c and recompile!");
448                 return (-1);
449         }
450         return (first_free_schilly_bus);
451 }
452
453 static int
454 usalo_amerge(char *path, char *readedlink, char *buffer, int buflen)
455 {
456         char    *aa;
457
458 #define TOKEN_ARRAY             20
459 #define LAST_CHAR(x)            (x)[strlen((x))-1]
460 #define ONE_CHAR_BACK(x)        (x)[strlen((x))-1] = '\0'
461         char    *ppa[TOKEN_ARRAY];
462         char    *pa;
463
464         int     i;
465         int     len;
466         char    seps[] = "/";
467         char    *last_slash;
468
469         if (!path || !readedlink || !buffer)
470                 return (-EINVAL);
471
472         if ('/' == readedlink[0]) {
473                 aa = (char *) malloc(strlen(readedlink) + 1);
474                 if (!aa)
475                         return (-ENOMEM);
476
477                 strcpy(aa, readedlink);
478         } else {
479                 aa = (char *) malloc(strlen(path) + strlen(readedlink) + 1);
480                 if (!aa)
481                         return (-ENOMEM);
482
483                 strcpy(aa, path);
484                 if (LAST_CHAR(aa) == '/') {
485                         ONE_CHAR_BACK(aa);
486                 }
487                 last_slash = strrchr(aa, '/');
488                 if (last_slash == NULL)
489                         strcpy(aa, "/");
490                 else
491                         *(++last_slash) = '\0';
492                 strcat(aa, readedlink);
493         }
494         memset(ppa, 0x00, sizeof (ppa));
495
496         for (i = 0, pa = strtok(aa, seps);
497                 i < TOKEN_ARRAY && pa != NULL;
498                 ++i, pa = strtok(NULL, seps)) {
499                 ppa[i] = pa;
500         }
501
502         if (i == TOKEN_ARRAY) {
503                 free(aa);
504                 return (-ENOMEM);
505         }
506         for (i = 0; i < TOKEN_ARRAY && ppa[i]; i++) {
507                 if (strcmp(ppa[i], "..") == 0) {
508                         ppa[i] = NULL;
509                         if (i > 1)
510                                 ppa[i - 1] = NULL;
511                 }
512         }
513
514         /* dry run */
515         len = 0;
516         for (i = 0; i < TOKEN_ARRAY; i++) {
517                 if (ppa[i]) {
518                         len += 1;
519                         len += strlen(ppa[i]);
520                 }
521         }
522         if (0 == len)
523                 len = 1;
524
525         if (len + 1 <= buflen) {
526                 strcpy(buffer, "");
527                 for (i = 0; i < TOKEN_ARRAY; i++) {
528                         if (ppa[i]) {
529                                 strcat(buffer, "/");
530                                 strcat(buffer, ppa[i]);
531                         }
532                 }
533
534                 if (strlen(buffer) == 0)
535                         strcpy(buffer, "/");
536         }
537         free(aa);
538
539         return (len + 1);
540 }
541
542 /*
543  *      /dev/cdroms/cdrom0      first CD-ROM
544  *      /dev/cdroms/cdrom1      second CD-ROM
545  *
546  *
547  *      SCSI Devices
548  *
549  *      To uniquely identify any SCSI device requires the following information:
550  *
551  *      controller      (host adapter)
552  *      bus             (SCSI channel)
553  *      target          (SCSI ID)
554  *      unit            (Logical Unit Number)
555  *
556  *      All SCSI devices are placed under /dev/scsi (assuming devfs is mounted on /dev).
557  *      Hence, a SCSI device with the following parameters:
558  *              c=1,b=2,t=3,u=4 would appear as:
559  *
560  *              /dev/scsi/host1/bus2/target3/lun4       device directory
561  *
562  *      Inside this directory, a number of device entries may be created,
563  *      depending on which SCSI device-type drivers were installed.
564  *
565  *      See the section on the disc naming scheme to see what entries
566  *      the SCSI disc driver creates.
567  *
568  *      See the section on the tape naming scheme to see what entries
569  *      the SCSI tape driver creates.
570  *
571  *      The SCSI CD-ROM driver creates:  cd
572  *      The SCSI generic driver creates: generic
573  *
574  *      IDE Devices
575  *
576  *      To uniquely identify any IDE device requires the following information:
577  *
578  *      controller
579  *      bus             (0/1 aka. primary/secondary)
580  *      target          (0/1 aka. master/slave)
581  *      unit
582  *
583  *      All IDE devices are placed under /dev/ide, and uses a similar
584  *      naming scheme to the SCSI subsystem.
585  *
586  *
587  *      Example /dev/cdroms/cdrom0 ->  /dev/scsi/host1/bus2/target3/lun4/cd
588  *      Example /dev/cdroms/cdrom1 ->  /dev/ide/host1/bus0/target1/lun4/cd
589  *
590  */
591 static BOOL
592 sg_amapdev(SCSI *usalp, int f, char *device, int *schillybus, int *target, 
593                           int *lun)
594 {
595         struct host {
596                 char    host[4];
597                 char    host_no;
598         };
599         struct bus {
600                 char    bus[3];
601                 char    bus_no;
602         };
603         struct target {
604                 char    target[6];
605                 char    target_no;
606         };
607         struct lun {
608                 char    lun[3];
609                 char    lun_no;
610         };
611
612         int     h,
613                 b,
614                 t,
615                 l;
616
617 #define TOKEN_DEV               "dev"
618 #define TOKEN_SUBSYSTEM_SCSI    "scsi"
619 #define TOKEN_SUBSYSTEM_IDE     "ide"
620 #define TOKEN_HOST              "host"
621 #define TOKEN_BUS               "bus"
622 #define TOKEN_TARGET            "target"
623 #define TOKEN_LUN               "lun"
624 #define TOKEN_CD                "cd"
625
626 #define ID_TOKEN_DEV            0
627 #define ID_TOKEN_SUBSYSTEM      1
628 #define ID_TOKEN_HOST           2
629 #define ID_TOKEN_BUS            3
630 #define ID_TOKEN_TARGET         4
631 #define ID_TOKEN_LUN            5
632 #define ID_TOKEN_CD             6
633 #define ID_TOKEN_LAST           ID_TOKEN_CD
634 #define ID_TOKEN_MAX            ID_TOKEN_LAST + 2
635 #define CHARTOINT(x)            (abs(atoi(&x)))
636
637         char            *token[ID_TOKEN_MAX],
638                         *seps = "/";
639         int             i,
640                         result;
641         struct stat     buf;
642
643 #ifndef MAX_PATH
644 #define MAX_PATH 260
645 #endif
646 #define LOCAL_MAX_PATH MAX_PATH
647         char            tmp[LOCAL_MAX_PATH],
648                         tmp1[LOCAL_MAX_PATH];
649         int             first_free_schilly_bus;
650         int             subsystem = HOST_EMPTY;
651
652         /* old DEV */
653         typedef struct {
654                 char            prefix[2];
655                 char            device;
656         } old_dev;
657         /* strtok need char* instead of const char* */
658         result = stat(device, &buf);
659         if (result || !S_ISBLK(buf.st_mode))
660                 return (FALSE);
661
662         result = lstat(device, &buf);
663         if (!result && S_ISLNK(buf.st_mode)) {
664                 result = readlink(device, tmp, LOCAL_MAX_PATH);
665                 if (result > 0 && result < LOCAL_MAX_PATH) {
666                         tmp[result] = '\0';
667
668                         result = usalo_amerge(device, tmp, tmp1, LOCAL_MAX_PATH);
669                         if (result > 0 && result < LOCAL_MAX_PATH) {
670                                 tmp1[result] = '\0';
671                                 strcpy(tmp, tmp1);
672                         } else {
673                                 errmsgno(EX_BAD,
674                                 "ERROR: with link merging! base %s link %s, result of merging %i\n",
675                                         device, tmp, result);
676                                 return (FALSE);
677                         }
678                 } else {
679                         errmsgno(EX_BAD,
680                         "ERROR: with link reading! link %s, result of readlink %i\n",
681                                 device, result);
682                         return (FALSE);
683                 }
684         } else {
685                 strncpy(tmp, device, sizeof (tmp));
686         }
687         if (usalp->debug > 3) {
688                 fprintf((FILE *) usalp->errfile, "INFO: %s -> %s\n", device, tmp);
689         }
690         memset(token, 0x00, sizeof (token));
691         i = 0;
692         token[i] = strtok(tmp, seps);
693         while (token[i] != NULL && (++i) && i < ID_TOKEN_MAX) {
694                 token[i] = strtok(NULL, seps);
695         }
696
697         if (i == ID_TOKEN_MAX ||
698                 !(token[ID_TOKEN_DEV]) ||
699                 strcmp(token[ID_TOKEN_DEV], TOKEN_DEV)) {
700
701                 errmsgno(EX_BAD, "ERROR: unknown format\n");
702                 errmsgno(EX_BAD, "EXAMPLE: /dev/scsi/host1/bus2/target3/lun4/cd\n");
703                 errmsgno(EX_BAD, "EXAMPLE: /dev/ide/host0/bus0/target1/lun0/cd\n");
704                 errmsgno(EX_BAD, "EXAMPLE: /dev/hda or /dev/sr0\n");
705                 return (FALSE);
706         }
707         if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_SCSI)) ||
708             !(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_IDE))) {
709                 h = CHARTOINT(((struct host *) token[ID_TOKEN_HOST])->host_no);
710                 b = CHARTOINT(((struct bus *) token[ID_TOKEN_BUS])->bus_no);
711                 t = CHARTOINT(((struct target *) token[ID_TOKEN_TARGET])->target_no);
712                 l = CHARTOINT(((struct lun *) token[ID_TOKEN_LUN])->lun_no);
713 #ifdef PARANOID
714                 if (strncmp(token[ID_TOKEN_HOST], TOKEN_HOST, strlen(TOKEN_HOST))) {
715                         log(("ERROR: invalid host specified\n"));
716                         return (FALSE);
717                 }
718                 if (strncmp(token[ID_TOKEN_BUS], TOKEN_BUS, strlen(TOKEN_BUS))) {
719                         log(("ERROR: invalid bus specified\n"));
720                         return (FALSE);
721                 }
722                 if (strncmp(token[ID_TOKEN_TARGET], TOKEN_TARGET, strlen(TOKEN_TARGET))) {
723                         log(("ERROR: invalid target specified\n"));
724                         return (FALSE);
725                 }
726                 if (strncmp(token[ID_TOKEN_LUN], TOKEN_LUN, strlen(TOKEN_LUN))) {
727                         log(("ERROR: invalid lun specified\n"));
728                         return (FALSE);
729                 }
730                 if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_IDE))) {
731                         if (b > 1 || t > 1) {
732                                 log(("ERROR: invalid bus or target for IDE specified\n"));
733                                 return (FALSE);
734                         }
735                 }
736 #endif  /* PARANOID */
737
738                 if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_IDE))) {
739                         subsystem = HOST_IDE;
740                 } else if (!(strcmp(token[ID_TOKEN_SUBSYSTEM], TOKEN_SUBSYSTEM_SCSI))) {
741                         subsystem = HOST_SCSI;
742                 } else {
743                         subsystem = HOST_OTHER;
744                 }
745         } else if (!token[ID_TOKEN_HOST] &&
746                 strlen(token[ID_TOKEN_SUBSYSTEM]) == sizeof (old_dev)) {
747                 char    j;
748
749                 old_dev *pDev = (old_dev *) token[ID_TOKEN_SUBSYSTEM];
750
751                 if (strncmp(pDev->prefix, "hd", 2) == 0) {
752                         j = pDev->device - ('a');
753
754                         subsystem = HOST_IDE;
755                         h = j / 4;
756                         b = (j % 4) / 2;
757                         t = (j % 4) % 2;
758                         l = 0;
759                 } else if (strncmp(pDev->prefix, "sr", 2) == 0) {
760 #ifdef  nonono
761                         if (pDev->device >= '0' && pDev->device <= '9')
762                                 j = pDev->device - ('0');
763                         else
764                                 j = pDev->device - ('a');
765
766
767                         h = j / 4;
768                         b = (j % 4) / 2;
769                         t = (j % 4) % 2;
770                         l = 0;
771 #endif  /* nonono */
772                         /* other solution, with ioctl */
773                         int     Chan = 0,
774                                 Ino = 0,
775                                 Bus = 0,
776                                 Target = 0,
777                                 Lun = 0;
778
779                         subsystem = HOST_SCSI;
780                         sg_amapdev_scsi(usalp, f, &Bus, &Target, &Lun, &Chan, &Ino);
781
782                         /* For old kernels try to make the best guess. */
783 #ifdef  nonono
784                                 int     n;
785                                 Ino |= Chan << 8;
786                                 n = sg_mapbus(usalp, Bus, Ino);
787                                 if (Bus == -1) {
788                                         Bus = n;
789                                         if (usalp->debug > 0) {
790                                                 fprintf((FILE *)usalp->errfile,
791                                                         "SCSI Bus: %d (mapped from %d)\n",
792                                                         Bus, Ino);
793                                         }
794                                 }
795 /*                              It is me too high ;-()*/
796 #endif  /* nonono */
797                         h = Ino;
798                         b = Chan;
799                         t = Target;
800                         l = Lun;
801                 } else {
802                         errmsgno(EX_BAD, "ERROR: unknow subsystem (%s) in (%s)\n",
803                                 token[ID_TOKEN_SUBSYSTEM], device);
804                         return (FALSE);
805                 }
806         } else {
807                 errmsgno(EX_BAD, "ERROR: unknow subsystem (%s) in (%s)\n",
808                         token[ID_TOKEN_SUBSYSTEM], device);
809                 return (FALSE);
810         }
811
812         if (usalp->verbose)
813                 printf(usalp->errstr, "INFO: subsystem %s: h %i, b %i, t %i, l %i",
814                         token[ID_TOKEN_SUBSYSTEM], h, b, t, l);
815
816         first_free_schilly_bus = usalo_aget_first_free_shillybus(usalp, subsystem, h, b);
817         if (-1 == first_free_schilly_bus) {
818                 return (FALSE);
819         }
820         if (usallocal(usalp)->usalfiles[first_free_schilly_bus][t][l] != (-1)) {
821                 errmsgno(EX_BAD, "ERROR: this cdrom is already mapped %s(%d,%d,%d)\n",
822                         device, first_free_schilly_bus, t, l);
823                 return (FALSE);
824         } else {
825                 usallocal(usalp)->usalfiles[first_free_schilly_bus][t][l] = f;
826                 typlocal(usalp, first_free_schilly_bus) = subsystem;
827                 hostlocal(usalp, first_free_schilly_bus) = h;
828                 buslocal(usalp, first_free_schilly_bus) = b;
829                 *schillybus = first_free_schilly_bus;
830                 *target = t;
831                 *lun = l;
832
833                 if (usalp->debug > 1) {
834                         fprintf((FILE *) usalp->errfile,
835                                 "INFO: /dev/%s, (host%d/bus%d/target%d/lun%d) will be mapped on the schilly bus No %d (%d,%d,%d)\n",
836                                 token[ID_TOKEN_SUBSYSTEM], h, b, t, l,
837                                 first_free_schilly_bus, first_free_schilly_bus, t, l);
838                 }
839         }
840         return (TRUE);
841 }
842
843 static BOOL
844 sg_amapdev_scsi(SCSI *usalp, int f, int *busp, int *tgtp, int *lunp, 
845                                          int *chanp, int *inop)
846 {
847         struct sg_id {
848                 long    l1;     /* target | lun << 8 | channel << 16 | low_ino << 24 */
849                 long    l2;     /* Unique id */
850         } sg_id;
851         int     Chan;
852         int     Ino;
853         int     Bus;
854         int     Target;
855         int     Lun;
856
857         if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id))
858                 return (FALSE);
859
860         if (usalp->debug > 0) {
861                 fprintf((FILE *) usalp->errfile,
862                         "INFO: l1: 0x%lX l2: 0x%lX\n", sg_id.l1, sg_id.l2);
863         }
864         if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) {
865                 Bus = -1;
866         }
867         Target = sg_id.l1 & 0xFF;
868         Lun = (sg_id.l1 >> 8) & 0xFF;
869         Chan = (sg_id.l1 >> 16) & 0xFF;
870         Ino = (sg_id.l1 >> 24) & 0xFF;
871         if (usalp->debug > 0) {
872                 fprintf((FILE *) usalp->errfile,
873                         "INFO: Bus: %d Target: %d Lun: %d Chan: %d Ino: %d\n",
874                         Bus, Target, Lun, Chan, Ino);
875         }
876         *busp = Bus;
877         *tgtp = Target;
878         *lunp = Lun;
879         if (chanp)
880                 *chanp = Chan;
881         if (inop)
882                 *inop = Ino;
883         return (TRUE);
884 }
885
886 static long
887 usalo_amaxdma(SCSI *usalp, long amt)
888 {
889         /*
890          * EINVAL (hart) ENOMEM (weich) bei mehr ...
891          * Bei fehlerhaftem Sense Pointer kommt EFAULT
892          */
893         return (MAX_DMA_ATA);
894 }
895
896 static BOOL
897 usalo_ahavebus(SCSI *usalp, int busno)
898 {
899         register int    t;
900         register int    l;
901
902         if (busno < 0 || busno >= MAX_SCHILLY_HOSTS)
903                 return (FALSE);
904
905         if (usalp->local == NULL)
906                 return (FALSE);
907
908         for (t = 0; t < MAX_TGT; t++) {
909                 for (l = 0; l < MAX_LUN; l++)
910                         if (usallocal(usalp)->usalfiles[busno][t][l] >= 0)
911                                 return (TRUE);
912         }
913         return (FALSE);
914 }
915
916 static int
917 usalo_afileno(SCSI *usalp, int busno, int tgt, int tlun)
918 {
919         if (busno < 0 || busno >= MAX_SCHILLY_HOSTS ||
920                 tgt < 0 || tgt >= MAX_TGT ||
921                 tlun < 0 || tlun >= MAX_LUN)
922                 return (-1);
923
924         if (usalp->local == NULL)
925                 return (-1);
926
927         return ((int) usallocal(usalp)->usalfiles[busno][tgt][tlun]);
928 }
929
930 static int
931 usalo_ainitiator_id(SCSI *usalp)
932 {
933         printf(usalp->errstr, "NOT IMPELEMENTED: usalo_initiator_id");
934         return (-1);
935 }
936
937 static int
938 usalo_aisatapi(SCSI *usalp)
939 {
940         int schillybus = usalp->addr.scsibus;
941         int typ = typlocal(usalp, schillybus);
942         if (typ == HOST_EMPTY)
943                 return (-1);
944         if (typ != HOST_SCSI)
945                 return (1);
946         else
947                 return (0);
948 }
949
950 static int
951 usalo_areset(SCSI *usalp, int what)
952 {
953         if (what == SCG_RESET_NOP)
954                 return (0);
955
956         if (what == SCG_RESET_TGT || what == SCG_RESET_BUS)
957                 return (ioctl(what, CDROMRESET));
958
959         return (-1);
960 }
961
962 static int
963 usalo_asend(SCSI *usalp)
964 {
965         struct usal_cmd *sp = usalp->scmd;
966         int             ret,
967                         i;
968         struct cdrom_generic_command sg_cgc;
969         struct request_sense sense_cgc;
970
971 #ifdef DEBUG
972         char            tmp_send[340],
973                         tmp_read[340],
974                         tmp_sense[340],
975                         tmp1[30];
976         int             j;
977         char            *p;
978 #endif
979
980         if (usalp->fd < 0) {
981                 sp->error = SCG_FATAL;
982                 sp->ux_errno = EIO;
983                 return (0);
984         }
985         if (sp->cdb_len > CDROM_PACKET_SIZE) {
986                 sp->error = SCG_FATAL;
987                 sp->ux_errno = EIO;
988                 return (0);
989         }
990         /* initialize */
991         fillbytes((caddr_t) & sg_cgc, sizeof (sg_cgc), '\0');
992         fillbytes((caddr_t) & sense_cgc, sizeof (sense_cgc), '\0');
993
994         if (sp->flags & SCG_RECV_DATA) {
995                 sg_cgc.data_direction = CGC_DATA_READ;
996         } else if (sp->size > 0) {
997                 sg_cgc.data_direction = CGC_DATA_WRITE;
998         } else {
999                 sg_cgc.data_direction = CGC_DATA_NONE;
1000         }
1001 #if LINUX_VERSION_CODE >= 0x020403
1002         if (sp->flags & SCG_SILENT) {
1003                 sg_cgc.quiet = 1;
1004         }
1005 #endif
1006         for (i = 0; i < sp->cdb_len; i++) {
1007                 sg_cgc.cmd[i] = sp->cdb.cmd_cdb[i];
1008         }
1009
1010         sg_cgc.buflen = sp->size;
1011         sg_cgc.buffer = (unsigned char *)sp->addr;
1012
1013         if (sp->sense_len > sizeof (sense_cgc))
1014                 sense_cgc.add_sense_len = sizeof (sense_cgc) - 8;
1015         else
1016                 sense_cgc.add_sense_len = sp->sense_len - 8;
1017
1018         sg_cgc.sense = &sense_cgc;
1019 #if LINUX_VERSION_CODE >= 0x020403
1020         sg_cgc.timeout = sp->timeout * 1000;
1021 #endif
1022 #ifdef DEBUG
1023         strcpy(tmp_send, "send cmd:\n");
1024         for (j = 0; j < sp->cdb_len; j++) {
1025                 sprintf(tmp1, " %02X", sp->cdb.cmd_cdb[j]);
1026                 strcat(tmp_send, tmp1);
1027         }
1028         strcat(tmp_send, "\n");
1029
1030         if (sg_cgc.data_direction == CGC_DATA_WRITE) {
1031                 int     z;
1032
1033                 sprintf(tmp1, "data_write: %i bytes\n", sp->size);
1034                 strcat(tmp_send, tmp1);
1035                 for (j = 0, z = 1; j < 80 && j < sp->size; j++, z++) {
1036                         if (z > 16) {
1037                                 z = 1;
1038                                 strcat(tmp_send, "\n");
1039                         }
1040                         sprintf(tmp1, " %02X", (unsigned char) (sp->addr[j]));
1041                         strcat(tmp_send, tmp1);
1042                 }
1043                 strcat(tmp_send, "\n");
1044
1045                 if (sp->size > 80) {
1046                         strcat(tmp_send, "...\n");
1047                 }
1048         }
1049 #endif  /* DEBUG */
1050         if ((ret = ioctl(usalp->fd, CDROM_SEND_PACKET, &sg_cgc)) < 0)
1051                 sp->ux_errno = geterrno();
1052
1053         if (ret < 0 && usalp->debug > 4) {
1054                 fprintf((FILE *) usalp->errfile,
1055                         "ioctl(CDROM_SEND_PACKET) ret: %d\n", ret);
1056         }
1057         /*
1058          * copy scsi data back
1059          */
1060         if (sp->flags & SCG_RECV_DATA && ((void *) sp->addr != (void *) sg_cgc.buffer)) {
1061                 memcpy(sp->addr, sg_cgc.buffer, (sp->size < sg_cgc.buflen) ? sp->size : sg_cgc.buflen);
1062                 if (sg_cgc.buflen > sp->size)
1063                         sp->resid = sg_cgc.buflen - sp->size;
1064         }
1065         sp->error = SCG_NO_ERROR;
1066 #ifdef DEBUG
1067         if (ret < 0) {
1068                 switch (sp->ux_errno) {
1069                 case ENOTTY:
1070                         p = "ENOTTY";
1071                         break;
1072                 case EINVAL:
1073                         p = "EINVAL";
1074                         break;
1075                 case ENXIO:
1076                         p = "ENXIO";
1077                         break;
1078                 case EACCES:
1079                         p = "EACCES";
1080                         break;
1081                 case EIO:
1082                         p = "EIO";
1083                         break;
1084                 case ENOMEDIUM:
1085                         p = "ENOMEDIUM";
1086                         break;
1087                 case EDRIVE_CANT_DO_THIS:
1088                         p = "EDRIVE_CANT_DO_THIS";
1089                         break;
1090                 default:
1091                         p = "UNKNOW";
1092                 };
1093                 log(("%s", tmp_send));
1094                 log(("ERROR: returns %i errno %i(%s)\n", ret, sp->ux_errno, p));
1095         }
1096 #endif  /* DEBUG */
1097         if (ret < 0) {
1098                 /*
1099                  * Check if SCSI command cound not be send at all.
1100                  * Linux usually returns EINVAL for an unknoen ioctl.
1101                  * In case somebody from the Linux kernel team learns that the
1102                  * corect errno would be ENOTTY, we check for this errno too.
1103                  */
1104                 if (sp->ux_errno == EINVAL) {
1105                         /*
1106                          * Try to work around broken Linux kernel design...
1107                          * If SCSI Sense Key is 0x05 (Illegal request), Linux
1108                          * returns a useless EINVAL making it close to
1109                          * impossible distinct from "Illegal ioctl()" or
1110                          * "Invalid parameter".
1111                          */
1112                         if ((((Uchar *)sg_cgc.sense)[0] != 0) ||
1113                             (((Uchar *)sg_cgc.sense)[2] != 0))
1114                                 sp->ux_errno = EIO;
1115
1116                 } else if ((sp->ux_errno == ENOTTY || sp->ux_errno == EINVAL)) {
1117                         /*
1118                          * May be "Illegal ioctl()".
1119                          */
1120                         return (-1);
1121                 }
1122                 if (sp->ux_errno == ENXIO || sp->ux_errno == EACCES) {
1123                         return (-1);
1124                 }
1125         } else if (ret == 0) {
1126 #ifdef DEBUG
1127                 if (sg_cgc.data_direction == CGC_DATA_READ) {
1128                         int     z;
1129
1130                         sprintf(tmp_read, "data_read: %i bytes\n", sp->size);
1131                         for (j = 0, z = 1; j < 80 && j < sp->size; j++, z++) {
1132                                 if (z > 16) {
1133                                         z = 1;
1134                                         strcat(tmp_read, "\n");
1135                                 }
1136                                 sprintf(tmp1, " %02X", (unsigned char) (sp->addr[j]));
1137                                 strcat(tmp_read, tmp1);
1138                         }
1139                         strcat(tmp_read, "\n");
1140                         if (sp->size > 80) {
1141                                 strcat(tmp_read, "...\n");
1142                         }
1143                 }
1144 #endif  /* DEBUG */
1145         }
1146         /*
1147          * copy sense back
1148          */
1149         if (ret < 0 && sg_cgc.sense->error_code) {
1150                 sp->sense_count = sense_cgc.add_sense_len + 8;
1151 #ifdef DEBUG
1152                 sprintf(tmp_sense, "sense_data: length %i\n", sp->sense_count);
1153                 for (j = 0; j < sp->sense_count; j++) {
1154                         sprintf(tmp1, " %02X", (((unsigned char *) (&sense_cgc))[j]));
1155                         strcat(tmp_sense, tmp1);
1156                 }
1157                 log(("%s\n", tmp_sense));
1158
1159                 sprintf(tmp_sense, "sense_data: error code 0x%02X, sense key 0x%02X,"
1160                         " additional length %i, ASC 0x%02X, ASCQ 0x%02X\n",
1161                         sg_cgc.sense->error_code, sg_cgc.sense->sense_key,
1162                         sg_cgc.sense->add_sense_len, sg_cgc.sense->asc,
1163                         sg_cgc.sense->ascq);
1164
1165                 log(("%s\n", tmp_sense));
1166 #endif  /* DEBUG */
1167                 memcpy(sp->u_sense.cmd_sense, /* (caddr_t) */ &sense_cgc, SCG_MAX_SENSE);
1168                 sp->u_scb.cmd_scb[0] = ST_CHK_COND;
1169
1170                 switch (sg_cgc.sense->sense_key) {
1171                 case SC_UNIT_ATTENTION:
1172                 case SC_NOT_READY:
1173                         sp->error = SCG_RETRYABLE;      /* may be BUS_BUSY */
1174                         sp->u_scb.cmd_scb[0] |= ST_BUSY;
1175                         break;
1176                 case SC_ILLEGAL_REQUEST:
1177                         break;
1178                 default:
1179                         break;
1180                 }
1181         } else {
1182                 sp->u_scb.cmd_scb[0] = 0x00;
1183         }
1184
1185         sp->resid = 0;
1186         return (0);
1187 }
1188 #endif  /* USE_OLD_ATAPI */