[446] in linux-scsi channel archive
Generic Scsi Driver Bug Report and comments.
daemon@ATHENA.MIT.EDU (Roland Dunkerley)
Tue Aug 1 03:33:14 1995
Date: Mon, 31 Jul 95 17:10:43 PDT
From: rolandd@swn.com (Roland Dunkerley)
To: mike@ringo.reno.nv.us (Michael Morrison)
Cc: linux-scsi@vger.rutgers.edu (linux scsi)
In-Reply-To: <m0sc56K-000SmpC@ringo>
>>>>> "}" == Michael Morrison <mike@ringo.reno.nv.us> writes:
}> This is a combination bug report and some general comments on
}> the scsi generic driver. I'll summarize the bugs at the end.
}> IMHO the generic scsi driver interface is a little clumsy. The
}> following comments point out these problems. I intend to make
}> the changes to the sg driver we use to provide a better
}> interface and device mapping stratagy. I will follow this
}> message up with a formal specification. But before I do, I'd
}> like comments from sg driver users. Do you agree with the
}> following comments? Would having another sg driver that is
}> based on the existing one but with a slightly different
}> interface and better error reporting be desirable?
I went over this, and I agree with some points and not with others.
I'll indicate my specific points below along with a few additions.
}> 1. Dynamic device mapping
}> [...]
}> For example, assuming you had three SCSI devices hooked up
}> with ids 1, 3, and 5 on the first SCSI bus (each having one
}> LUN), then the following mapping would be in effect:
}> /dev/sga -> SCSI id 1 /dev/sgb -> SCSI id 3 /dev/sgc ->
}> SCSI id 5
}> If you now add a new device with id 4, then the mapping
}> (after the next rescan) will be:
}> /dev/sga -> SCSI id 1 /dev/sgb -> SCSI id 3 /dev/sgc ->
}> SCSI id 4 /dev/sgd -> SCSI id 5
This is apparently taken from the way disks, tapes, and cdroms are
numbered. Such numbering does seem to make sense at that level of
abstraction, but perhaps not at the generic level we are presently
addressing. There are at least a couple of methods to
address this issue, one of which you present below, and one of which I
present as a possibly more flexible alternative. I wouldn't complain
to see either or both implemented, but I like mine better, perhaps
because it's my idea. :)
}> I believe this method of device mapping is not the best
}> way. A better way would to map devices as follows:
}> /dev/sg00 -> Controller 0, Id 0 /dev/sg01 -> Controller 0,
}> Id 1 /dev/sg10 -> Controller 1, Id 0 /dev/sg11 -> Controller 1,
}> Id 1 etc.
}> [... explanation of why current mapping is a problem]
}> My application code wants to talk to the "exotic" device at
}> SCSI id 6, but there is no way to assertain which generic
}> device name this is mapped to without scanning the whole bus.
How do you tell even then unless you open each sg device in turn (pty
style) and send an inquiry to the device to determine what it is?
}> Our application software typically has command line arguments
}> for controller number and target id. It is impossible to
}> translate controller number and target id to a device file name
}> in the current scheme.
This is a true criticism, I believe.
}> The Linux generic driver device mappings is also very
}> different from other workstation's generic drivers (sgi, HP)
}> which map devices to to specific device names based on
}> controller number and target id.
First, interfaces at this level are not addressed by POSIX, etc. So,
there being no standards to follow, there is no reason why linux
should work the way any other vendor's generic low level interface
works. We should do it better, whether that is similar or not. That
being said, it is also true that there is a real need to be able to
address a scsi target via it's (full or partial) nexus (bus, target,
lun, queue). This could be accomplished via a /dev/ mapping of the
form you describe (/dev/sg_c_t_l), but I think it may be better to
support (in addition to or in lieu of) opening a channel to the
generic driver without specifying a nexus
(open("/dev/sg",O_RDWR|O_EXCL); or equivalent) and then support nexus
specification via an ioctl interface. Perhaps there are commands
which would make sense before nexus specification as well (SIO_RESET
to reset all SCSI busses if not connected to a nexus, or to reset only
the specified bus if connected to a controller, or to reset only the
specified device if the target id has been set?). I think this would
provide greater flexibility and would make writing a generic SCSI
utility much easier as well.
}> 2. Generic Driver Interface.
}> The interface requires the application to fill in a buffer
}> with the sg_header structure, followed by the scsi command
}> string, then the data to be transfered. Our application code
}> runs on top of a 'very generic' level of code that has
}> functions like scsiWrite10, scsiWrite6, inquiry etc. These
}> functions must interface to the generic scsi drivers on a
}> number of different workstations, (Linux, sgi, HP, DOS ASPI).
}> This means that the application level code can't know about the
}> underlying generic driver's implementation. The problem is
}> that I must copy the data buffer from the application code to
}> the a buffer destined for the generic driver. This of course
}> causes a less efficient data transfer. A better way is to add
}> a pointer to the sg_header structure that points at the
}> application's data buffer. By examining the generic driver
}> source code one can see that it assigns a pointer to the data
}> buffer passed to it after doing some math to figure out the
}> offset in the buffer. So why not just give it a pointer and
}> avoid the math. The same thing happens with the command string
}> that immediatly follows the sg_header.
This would break the semantics of the write() system call, and if done
should be done through an ioctl which more closely matches the
semantics you are describing. (write should only use the data
explicitly passed to it, magic parameter passing through write is ugly
IMHO.) An alternative to implementing it as an ioctl would be to
allow the parameter to be passed in multiple calls to write (one for
the sg_header, one for the command, and one for the data; or perhaps
just one for sg_header+command and a second for the data). An
alternative for your application could be to allocate extra space for
the header and write after it, but this would break any page alignment
you might be expecting and again probably result in slower IO. Would
be truely nice if you could get DMAable buffers from the kernel to use
for IO to prevent all data copying. (Not that I think this is
happening soon, just wishful thinking really.)
}> 3. Error propagation
}> Error propagation is lacking because the error code
}> returned up from the lower level drivers is cleared in scsi
}> generic driver's sg_read() function. This seriously reduces
}> the error information that gets returned to the application.
}> All you get is 16 bytes of sense data.
This I completely agree with, better error propagation would be very
nice. Since we are working with a generic interface it would be nice
if we could get all scsi messages from the device passed to us as
well.
}> The only changes I am suggesting are a different device mapping
}> scheme, the addition of some additional fields to the sg_header
}> structure and propagation of errors.
If you're going to redo the SCSI generic interface, it would be nice
to be able to send arbitrary messages to the device as well, either
with or without a command. The specific message I need to send myself
is a bus device reset, which I may end up implementing just that one
out of necessity, but arbitrary messages would be nicer. Myself I
would welcome most any subset of these changes except the one which
would break the semantics of write(), I think that would be a bad
thing. I could help test any changes you make and perhaps contribute
in some small way, but I don't think Securicor would be willing to pay
for too much in the way of me developing on something like this. If I
can use something like this, it's fine with them, but if it requires
major non-product development, I don't think it would fly.
}> Bug List: (1.3.9)
}> 1. When the sg_command_done() function is called from the
}> lower level driver upon command completion, the
}> sg_header.result field is conditionally updated from the result
}> of the lower level drivers result. [...]
}> Personnaly, I'd rather get as much error information as
}> possible and and have the option of ignoring it.
}> 2. Using the default configuration (SG_BIG_BUFF ==
}> 32768). A read or write of data buffers with size > 32256 <
}> 32768 will fail. This is because the code in sg_write rounds
}> the buffer size up to the next 512 byte boundary which is 32768
}> in this case. In sg_malloc some code checks if the buffer size
}> is < SG_BIG_BUFF. Since the buffer size is == SG_BIG_BUFF, the
}> sg_malloc function fails.
Don't forget the bus reset on RESERVATION_CONFLICT, that's at least a
misfeature if not a bug.
NSA: South Africa Serbian Saddam Hussein AK-47 PLO [Hello to all my
fans in domestic surveillance] KGB Semtex Clinton explosion genetic
Cocaine Kennedy domestic disruption plutonium
This message copyright (c) Roland Pleasant Dunkerley III rolandd@swn.com
<A HREF="http://www.cdt.org/petition.html">Petition to Help keep FCC away
from inet!</A> Distribution of this article via Microsoft Network requires
payment of a $1.00(US) per character per copy license fee.