"T. Ribbrock" wrote: > > On Fri, Jan 10, 2003 at 01:46:55PM +0100, T. Ribbrock wrote: > [...] > > Hm. I am by no means an expert in any way, but I'd naively assume that > > this type of problem must have been encountered (and maybe solved) by > > other programs as well? I wonder how things like cdrecord or suchlike > > work on these platforms. Mind you, I'm just brainstorming a bit... :-} > [...]
Hmmm. Are you sure that cdrecord works as a 32 bit application on a 64 bit Linux kernel using the SG interface? > > While I'm at it (the brainstorming, I mean) - I had a look at the > cdrecord source - besides the fact the Joerg Schilling doesn't seem to > happy with Linux' sg driver :-} I noticed that he's got some code in > his scsi-linux with regard to misalignment, especially for non-ix86 - > could that be something? Shot in the dark, I know... Well, some issues regarding misalignment might emerge, when you try to build 64 bit-aligned 64-but-variables in a 32-bit environment. But the point, where the SG driver complains, is different: Sane uses the SG3 interface. This means to define a variable of type strct sg_io_hdr, defined in sg.h, to fill in the proper value and to issue a write() call for an SG device with this variable. struct sg_io_hdr is defined as: typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ void * dxferp; /* [i], [*io] points to data transfer memory or scatter gather list */ unsigned char * cmdp; /* [i], [*i] points to command to perform */ unsigned char * sbp; /* [i], [*o] points to sense_buffer memory */ unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */ int pack_id; /* [i->o] unused internally (normally) */ void * usr_ptr; /* [i->o] unused internally */ unsigned char status; /* [o] scsi status */ unsigned char masked_status;/* [o] shifted, masked scsi status */ unsigned char msg_status; /* [o] messaging level data (optional) */ unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ unsigned short host_status; /* [o] errors from host adapter */ unsigned short driver_status;/* [o] errors from software driver */ int resid; /* [o] dxfer_len - actual_transferred */ unsigned int duration; /* [o] time taken by cmd (unit: millisec) */ unsigned int info; /* [o] auxiliary information */ } sg_io_hdr_t; So, basically bunch of pointers, integers and chars. What sanei_scsi.c does is this (things like queue manegement, sg driver version detection and other stuff stripped off): struct sg_io_hdr sg_hdr; int fd; /* file handle of an SG device file */ int res; /' init sg_hdr */ res = write(fd, &sg_hdr, sizeof(sg_hdr)); if (res < 0) {/* bail out */} One of the first things done by the SG driver is to check, if the 3rd parameter of the write call, i.e., the write size, equals sizeof(sg_io_hdr). If this is not the case, errno is set to EINVAL (22 for SPARC Linux). And exactly this happens, because sizeof(sg_io_hdr) is different for 32 bit and 64 bit programs. So, what you can do: 1. compile Sane as a 64-bit application. In this case, sizeof(sg_io_hdr) should be the same both in the application and in the kernel. (OK, I understand that this might waste some disk space for duplicates of libc and friends.) 2. Don't use struct sg_io_hdr as defined in sg.h, but build your own struct, which is 64-bit-aware. I don't have any experience running 32 bit apps on top a 64 bit kernel, so I can't give any precise recipes. But let's assume that you can use something like a "long pointer", i.e. "long void * usr_ptr;" Then you can define a replacement for struct sg_io_hdr, which might be accepted by the SG driver. This probably also involves to check, if ints are 32 bit or 64 bit values, and if padding bytes must be inserted for example between "unsigned short iovec_count;" and "unsigned int dxfer_len;" in order to maintain proper 64 bit alignment. When you got all this resolved, you can try to call the SG driver from Sane again. For test purposes, you can add a few printk statements to the SG driver and some DBG statements to sanei_scsi.c in order to check, if the values are properly passed. Another problem with might be, how the 32bit application address space is mapped into the kernel's 64 bit address space. Look at the kernel functions __copy_from_user and __copy_to_user to figure out, if the pointers might need any special treatment. 3. Use the old SG interface. To do that, figure out, if the kernel works with 32 bit ints or with 64 bit ints. 3.1 If the kernel works with 32 bit ints, simply change all "#ifdef SG_IO" in sanei_scsi.c to "#ifdef XSG_IO" or so and compile Sane again. Sane will then use the old SG interface, which should be a bit easier to handle. 3.2 If the kernel works with 64 bit ints, figure out, how you can define a 32-bit replacement for struct sg_header (also defined in sg.h), so that this new struct defines somethingm which, when thrown into a write() call, will be accepted by the SG driver as a proper 64-bit struct sg_header. This will probably mainly mean to replace "int" with "long int". But remember that you might need to insert some padding bytes in order to achive proper 64-alignments. If everything looks fine, proceed as in 3.1. I'd prefer (1) or (2), because the SG3 interface is much cleaner than the old interface, but it might be a bit easier, because the the old interface did paass any pointers to the driver. Abel