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-linux-ata.c 1.7 04/06/12 Copyright 2002 J. Schilling */
15 * Interface for Linux generic SCSI implementation (sg).
17 * This is the interface for the broken Linux SCSI generic driver.
18 * This is a hack, that tries to emulate the functionality
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) 2002 J. Schilling
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
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.
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.
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.
56 #define ata_sccsid "obsolete ATAPI driver in cdrkit"
58 static char _usal_atrans_version[] = "scsi-linux-ata.c-1.7"; /* The version for ATAPI transport*/
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);
72 static usal_ops_t ata_ops = {
79 usalo_getbuf, /* Shared with SG driver */
80 usalo_freebuf, /* Shared with SG driver */
88 #define HOST_EMPTY 0xF
92 #define HOST_IEEE1389 0x3
93 #define HOST_PARALLEL 0x4
94 #define HOST_OTHER 0xE
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
101 #define MAX_DMA_ATA (131072-1) /* EINVAL (hart) ENOMEM (weich) bei mehr ... */
102 /* Bei fehlerhaftem Sense Pointer kommt EFAULT */
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,
111 static int usalo_amerge(char *path, char *readedlink, char *buffer, int buflen);
114 * uncomment this when you will get a debug file #define DEBUG
117 #define LOGFILE "scsi-linux-ata.log"
118 #define log(a) sglog a
120 static void sglog(const char *fmt, ...);
126 sglog(const char *fmt, ...)
129 FILE *f = fopen(LOGFILE, "a");
135 vfprintf(f, fmt, args);
143 static int scan_internal(SCSI * usalp, int *fatal);
146 * Return version information for the low level SCSI transport code.
147 * This has been introduced to make it easier to trace down problems
151 usalo_aversion(SCSI *usalp, int what)
153 if (usalp != (SCSI *)0) {
157 return (_usal_atrans_version);
159 * If you changed this source, you are not allowed to
160 * return "schily" for the SCG_AUTHOR request.
163 return (_usal_auth_cdrkit);
172 usalo_ahelp(SCSI *usalp, FILE *f)
174 __usal_help(f, "ATA", "ATA Packet specific SCSI transport",
175 "ATAPI:", "bus,target,lun", "ATAPI:1,2,0", TRUE, FALSE);
180 usalo_aopen(SCSI *usalp, char *device)
182 int bus = usal_scsibus(usalp);
183 int target = usal_target(usalp);
184 int lun = usal_lun(usalp);
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");
199 log(("\n<<<<<<<<<<<<<<<< LOGGING ON >>>>>>>>>>>>>>>>>\n"));
200 if (bus >= MAX_SCHILLY_HOSTS || target >= MAX_TGT || lun >= MAX_LUN) {
203 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
204 "Illegal value for bus, target or lun '%d,%d,%d'",
210 if (usalp->local == NULL) {
211 usalp->local = malloc(sizeof (struct usal_local));
212 if (usalp->local == NULL) {
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;
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;
235 if (device != NULL && strcmp(device, "ATAPI") == 0)
238 /* if not scanning */
239 if ((device != NULL && *device != '\0') || (bus == -2 && target == -2))
243 if (scan_internal(usalp, &nopen)) {
245 printf(usalp->errstr, "INFO: scan_internal(...) failed");
251 if (device != NULL && strncmp(device, "ATAPI:", 6) == 0)
253 if (usalp->debug > 3) {
254 fprintf((FILE *) usalp->errfile, "INFO: do usalo_open openbydev");
256 if (device != NULL && *device != '\0') {
261 f = sg_open_excl(device, O_RDONLY | O_NONBLOCK, FALSE);
265 snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
266 "Cannot open '%s'", device);
269 if (sg_amapdev(usalp, f, device, &schilly_bus, &starget, &slun)) {
270 usal_settarget(usalp, schilly_bus, starget, slun);
278 scan_internal(SCSI *usalp, int *nopen)
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
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);
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);
311 if (usalp->debug > 4) {
312 fprintf((FILE *) usalp->errfile,
313 "DEVFS not detected, continuing with old dev\n");
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",
324 fprintf((FILE *) usalp->errfile,
325 "try open(%s) return %i, errno %i, trying next cdrom\n",
329 if (usalp->debug > 4) {
330 fprintf((FILE *) usalp->errfile,
331 "try open(%s) return %i errno %i calling sg_mapdev(...)\n",
334 if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) {
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",
356 if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) {
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",
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",
385 } else if (sg_amapdev(usalp, f, device, &schilly_bus, &target, &lun)) {
397 usalo_aclose(SCSI *usalp)
404 if (usalp->local == NULL)
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];
414 usallocal(usalp)->usalfiles[h][t][l] = (short) -1;
419 if (usallocal(usalp)->xbuf != NULL) {
420 free(usallocal(usalp)->xbuf);
421 usallocal(usalp)->xbufsize = 0L;
422 usallocal(usalp)->xbuf = NULL;
424 log(("<<<<<<<<<<<<<<<< LOGGING OFF >>>>>>>>>>>>>>>>>\n\n"));
429 usalo_aget_first_free_shillybus(SCSI *usalp, int subsystem, int host, int bus)
431 int first_free_schilly_bus;
433 for (first_free_schilly_bus = 0;
434 first_free_schilly_bus < MAX_SCHILLY_HOSTS;
435 first_free_schilly_bus++) {
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))
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",
447 errmsgno(EX_BAD, "Increase MAX_SCHILLY_HOSTS in scsi-linux-ata.c and recompile!");
450 return (first_free_schilly_bus);
454 usalo_amerge(char *path, char *readedlink, char *buffer, int buflen)
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];
469 if (!path || !readedlink || !buffer)
472 if ('/' == readedlink[0]) {
473 aa = (char *) malloc(strlen(readedlink) + 1);
477 strcpy(aa, readedlink);
479 aa = (char *) malloc(strlen(path) + strlen(readedlink) + 1);
484 if (LAST_CHAR(aa) == '/') {
487 last_slash = strrchr(aa, '/');
488 if (last_slash == NULL)
491 *(++last_slash) = '\0';
492 strcat(aa, readedlink);
494 memset(ppa, 0x00, sizeof (ppa));
496 for (i = 0, pa = strtok(aa, seps);
497 i < TOKEN_ARRAY && pa != NULL;
498 ++i, pa = strtok(NULL, seps)) {
502 if (i == TOKEN_ARRAY) {
506 for (i = 0; i < TOKEN_ARRAY && ppa[i]; i++) {
507 if (strcmp(ppa[i], "..") == 0) {
516 for (i = 0; i < TOKEN_ARRAY; i++) {
519 len += strlen(ppa[i]);
525 if (len + 1 <= buflen) {
527 for (i = 0; i < TOKEN_ARRAY; i++) {
530 strcat(buffer, ppa[i]);
534 if (strlen(buffer) == 0)
543 * /dev/cdroms/cdrom0 first CD-ROM
544 * /dev/cdroms/cdrom1 second CD-ROM
549 * To uniquely identify any SCSI device requires the following information:
551 * controller (host adapter)
554 * unit (Logical Unit Number)
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:
560 * /dev/scsi/host1/bus2/target3/lun4 device directory
562 * Inside this directory, a number of device entries may be created,
563 * depending on which SCSI device-type drivers were installed.
565 * See the section on the disc naming scheme to see what entries
566 * the SCSI disc driver creates.
568 * See the section on the tape naming scheme to see what entries
569 * the SCSI tape driver creates.
571 * The SCSI CD-ROM driver creates: cd
572 * The SCSI generic driver creates: generic
576 * To uniquely identify any IDE device requires the following information:
579 * bus (0/1 aka. primary/secondary)
580 * target (0/1 aka. master/slave)
583 * All IDE devices are placed under /dev/ide, and uses a similar
584 * naming scheme to the SCSI subsystem.
587 * Example /dev/cdroms/cdrom0 -> /dev/scsi/host1/bus2/target3/lun4/cd
588 * Example /dev/cdroms/cdrom1 -> /dev/ide/host1/bus0/target1/lun4/cd
592 sg_amapdev(SCSI *usalp, int f, char *device, int *schillybus, int *target,
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"
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)))
637 char *token[ID_TOKEN_MAX],
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;
657 /* strtok need char* instead of const char* */
658 result = stat(device, &buf);
659 if (result || !S_ISBLK(buf.st_mode))
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) {
668 result = usalo_amerge(device, tmp, tmp1, LOCAL_MAX_PATH);
669 if (result > 0 && result < LOCAL_MAX_PATH) {
674 "ERROR: with link merging! base %s link %s, result of merging %i\n",
675 device, tmp, result);
680 "ERROR: with link reading! link %s, result of readlink %i\n",
685 strncpy(tmp, device, sizeof (tmp));
687 if (usalp->debug > 3) {
688 fprintf((FILE *) usalp->errfile, "INFO: %s -> %s\n", device, tmp);
690 memset(token, 0x00, sizeof (token));
692 token[i] = strtok(tmp, seps);
693 while (token[i] != NULL && (++i) && i < ID_TOKEN_MAX) {
694 token[i] = strtok(NULL, seps);
697 if (i == ID_TOKEN_MAX ||
698 !(token[ID_TOKEN_DEV]) ||
699 strcmp(token[ID_TOKEN_DEV], TOKEN_DEV)) {
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");
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);
714 if (strncmp(token[ID_TOKEN_HOST], TOKEN_HOST, strlen(TOKEN_HOST))) {
715 log(("ERROR: invalid host specified\n"));
718 if (strncmp(token[ID_TOKEN_BUS], TOKEN_BUS, strlen(TOKEN_BUS))) {
719 log(("ERROR: invalid bus specified\n"));
722 if (strncmp(token[ID_TOKEN_TARGET], TOKEN_TARGET, strlen(TOKEN_TARGET))) {
723 log(("ERROR: invalid target specified\n"));
726 if (strncmp(token[ID_TOKEN_LUN], TOKEN_LUN, strlen(TOKEN_LUN))) {
727 log(("ERROR: invalid lun specified\n"));
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"));
736 #endif /* PARANOID */
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;
743 subsystem = HOST_OTHER;
745 } else if (!token[ID_TOKEN_HOST] &&
746 strlen(token[ID_TOKEN_SUBSYSTEM]) == sizeof (old_dev)) {
749 old_dev *pDev = (old_dev *) token[ID_TOKEN_SUBSYSTEM];
751 if (strncmp(pDev->prefix, "hd", 2) == 0) {
752 j = pDev->device - ('a');
754 subsystem = HOST_IDE;
759 } else if (strncmp(pDev->prefix, "sr", 2) == 0) {
761 if (pDev->device >= '0' && pDev->device <= '9')
762 j = pDev->device - ('0');
764 j = pDev->device - ('a');
772 /* other solution, with ioctl */
779 subsystem = HOST_SCSI;
780 sg_amapdev_scsi(usalp, f, &Bus, &Target, &Lun, &Chan, &Ino);
782 /* For old kernels try to make the best guess. */
786 n = sg_mapbus(usalp, Bus, Ino);
789 if (usalp->debug > 0) {
790 fprintf((FILE *)usalp->errfile,
791 "SCSI Bus: %d (mapped from %d)\n",
795 /* It is me too high ;-()*/
802 errmsgno(EX_BAD, "ERROR: unknow subsystem (%s) in (%s)\n",
803 token[ID_TOKEN_SUBSYSTEM], device);
807 errmsgno(EX_BAD, "ERROR: unknow subsystem (%s) in (%s)\n",
808 token[ID_TOKEN_SUBSYSTEM], device);
813 printf(usalp->errstr, "INFO: subsystem %s: h %i, b %i, t %i, l %i",
814 token[ID_TOKEN_SUBSYSTEM], h, b, t, l);
816 first_free_schilly_bus = usalo_aget_first_free_shillybus(usalp, subsystem, h, b);
817 if (-1 == first_free_schilly_bus) {
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);
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;
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);
844 sg_amapdev_scsi(SCSI *usalp, int f, int *busp, int *tgtp, int *lunp,
845 int *chanp, int *inop)
848 long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */
849 long l2; /* Unique id */
857 if (ioctl(f, SCSI_IOCTL_GET_IDLUN, &sg_id))
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);
864 if (ioctl(f, SCSI_IOCTL_GET_BUS_NUMBER, &Bus) < 0) {
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);
887 usalo_amaxdma(SCSI *usalp, long amt)
890 * EINVAL (hart) ENOMEM (weich) bei mehr ...
891 * Bei fehlerhaftem Sense Pointer kommt EFAULT
893 return (MAX_DMA_ATA);
897 usalo_ahavebus(SCSI *usalp, int busno)
902 if (busno < 0 || busno >= MAX_SCHILLY_HOSTS)
905 if (usalp->local == NULL)
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)
917 usalo_afileno(SCSI *usalp, int busno, int tgt, int tlun)
919 if (busno < 0 || busno >= MAX_SCHILLY_HOSTS ||
920 tgt < 0 || tgt >= MAX_TGT ||
921 tlun < 0 || tlun >= MAX_LUN)
924 if (usalp->local == NULL)
927 return ((int) usallocal(usalp)->usalfiles[busno][tgt][tlun]);
931 usalo_ainitiator_id(SCSI *usalp)
933 printf(usalp->errstr, "NOT IMPELEMENTED: usalo_initiator_id");
938 usalo_aisatapi(SCSI *usalp)
940 int schillybus = usalp->addr.scsibus;
941 int typ = typlocal(usalp, schillybus);
942 if (typ == HOST_EMPTY)
944 if (typ != HOST_SCSI)
951 usalo_areset(SCSI *usalp, int what)
953 if (what == SCG_RESET_NOP)
956 if (what == SCG_RESET_TGT || what == SCG_RESET_BUS)
957 return (ioctl(what, CDROMRESET));
963 usalo_asend(SCSI *usalp)
965 struct usal_cmd *sp = usalp->scmd;
968 struct cdrom_generic_command sg_cgc;
969 struct request_sense sense_cgc;
981 sp->error = SCG_FATAL;
985 if (sp->cdb_len > CDROM_PACKET_SIZE) {
986 sp->error = SCG_FATAL;
991 fillbytes((caddr_t) & sg_cgc, sizeof (sg_cgc), '\0');
992 fillbytes((caddr_t) & sense_cgc, sizeof (sense_cgc), '\0');
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;
999 sg_cgc.data_direction = CGC_DATA_NONE;
1001 #if LINUX_VERSION_CODE >= 0x020403
1002 if (sp->flags & SCG_SILENT) {
1006 for (i = 0; i < sp->cdb_len; i++) {
1007 sg_cgc.cmd[i] = sp->cdb.cmd_cdb[i];
1010 sg_cgc.buflen = sp->size;
1011 sg_cgc.buffer = (unsigned char *)sp->addr;
1013 if (sp->sense_len > sizeof (sense_cgc))
1014 sense_cgc.add_sense_len = sizeof (sense_cgc) - 8;
1016 sense_cgc.add_sense_len = sp->sense_len - 8;
1018 sg_cgc.sense = &sense_cgc;
1019 #if LINUX_VERSION_CODE >= 0x020403
1020 sg_cgc.timeout = sp->timeout * 1000;
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);
1028 strcat(tmp_send, "\n");
1030 if (sg_cgc.data_direction == CGC_DATA_WRITE) {
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++) {
1038 strcat(tmp_send, "\n");
1040 sprintf(tmp1, " %02X", (unsigned char) (sp->addr[j]));
1041 strcat(tmp_send, tmp1);
1043 strcat(tmp_send, "\n");
1045 if (sp->size > 80) {
1046 strcat(tmp_send, "...\n");
1050 if ((ret = ioctl(usalp->fd, CDROM_SEND_PACKET, &sg_cgc)) < 0)
1051 sp->ux_errno = geterrno();
1053 if (ret < 0 && usalp->debug > 4) {
1054 fprintf((FILE *) usalp->errfile,
1055 "ioctl(CDROM_SEND_PACKET) ret: %d\n", ret);
1058 * copy scsi data back
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;
1065 sp->error = SCG_NO_ERROR;
1068 switch (sp->ux_errno) {
1087 case EDRIVE_CANT_DO_THIS:
1088 p = "EDRIVE_CANT_DO_THIS";
1093 log(("%s", tmp_send));
1094 log(("ERROR: returns %i errno %i(%s)\n", ret, sp->ux_errno, p));
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.
1104 if (sp->ux_errno == EINVAL) {
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".
1112 if ((((Uchar *)sg_cgc.sense)[0] != 0) ||
1113 (((Uchar *)sg_cgc.sense)[2] != 0))
1116 } else if ((sp->ux_errno == ENOTTY || sp->ux_errno == EINVAL)) {
1118 * May be "Illegal ioctl()".
1122 if (sp->ux_errno == ENXIO || sp->ux_errno == EACCES) {
1125 } else if (ret == 0) {
1127 if (sg_cgc.data_direction == CGC_DATA_READ) {
1130 sprintf(tmp_read, "data_read: %i bytes\n", sp->size);
1131 for (j = 0, z = 1; j < 80 && j < sp->size; j++, z++) {
1134 strcat(tmp_read, "\n");
1136 sprintf(tmp1, " %02X", (unsigned char) (sp->addr[j]));
1137 strcat(tmp_read, tmp1);
1139 strcat(tmp_read, "\n");
1140 if (sp->size > 80) {
1141 strcat(tmp_read, "...\n");
1149 if (ret < 0 && sg_cgc.sense->error_code) {
1150 sp->sense_count = sense_cgc.add_sense_len + 8;
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);
1157 log(("%s\n", tmp_sense));
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);
1165 log(("%s\n", tmp_sense));
1167 memcpy(sp->u_sense.cmd_sense, /* (caddr_t) */ &sense_cgc, SCG_MAX_SENSE);
1168 sp->u_scb.cmd_scb[0] = ST_CHK_COND;
1170 switch (sg_cgc.sense->sense_key) {
1171 case SC_UNIT_ATTENTION:
1173 sp->error = SCG_RETRYABLE; /* may be BUS_BUSY */
1174 sp->u_scb.cmd_scb[0] |= ST_BUSY;
1176 case SC_ILLEGAL_REQUEST:
1182 sp->u_scb.cmd_scb[0] = 0x00;
1188 #endif /* USE_OLD_ATAPI */