Subject: The thorpej_scsipi branch
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-kern
Date: 12/24/2000 19:20:26
Hi,
As you noticed I played a bit with the thorpej_scsipi branch in the last weeks.
Now I'd like to pull it up to the main branch soon, so it's time to start a
discussion here :)

The thorpej_scsipi branch is a rewritten mid-layer done by Jason a year
ago. We now have a clean separation between adapter, channel and periph
to avoid the scsipi_link mess. They're handled by a structure each,
scspi_adapter, scsipi_channel and scsipi_periph (see scsipiconf.h). The HBA
attaches an scsibus with a scspi_channel, which contains a pointer to a
scsipi_adapter. scsipi_adapter has pointers to callbacks to the HBA driver.
The most important one is adapt_request(), which allows the mid-layer to:
- request execution of a command (though a scsipi_xfer)
- request the HBA driver to grow resources for a given periph if possible.
- turn on tagged queuing, wide and sync negotiation. This is called once
  all lun for a target have been probed, which allows to allocate resources
  as needed.

Once a scsibus is attached, the mid layer starts probing target/lun, filling
in an array of scsipi_periph in the scsipi_channel when a device is
discovered and a driver for it has been attached. It's done once interrupts
are enabled, as with the current scsipi system.
The HBA can call scsipi_async_event() to notify the mid-layer of events
unrelated to current commands. Two events are currently defined:
- ASYNC_EVENT_MAX_OPENINGS: change the max number of outstanding commands
  for this periph
- ASYNC_EVENT_XFER_MODE: the sync/wide mode of the periph has changed.
These async events can be reported up to the upper layer driver by the
mid layer with a callback from scsipi_periph.

Commands are passed from the mid layer to the HBA though the adapt_request()
with a scsipi_xfer structure. once the command is done the HBA calls
scsipi_done(). Unlike the current scsipi, scsipi_done() can be called from
adapt_request() (or a function called by it), which reduces the difference
between polled and interrupt-driven command in the HBA driver.

Commands are queued in the mid layer, where per-periph and per-channel (or
per-adapter, the HBA driver can select one or the other) accounting is done.
This means that the HBA driver should never get a request if it doesn't
have the resources for it, and no queuing here is required.

Tags are manmaged in the mid-level, the HBA driver gets a request with the
tag type and tag id in the scsipi_xfer (or no tag at all, of course).
tag type can be selected by the upper lever driver; this means that the
sd driver can select between SIMPLE or ORDERED QUEUE TAG based on the
type of buffer.

Only commands with XS_NOERROR are handled by scsipi_done in interrupt
context. All other cases are handled by a kernel thread, which makes error
recovery (which may require requeing) much easier. Leaves handling of
RESET or QUEUE FULL events out of the HBA driver.

Of course all HBA drivers needs to be changed, but this is not such a big deal.
Only changing scsipi_cmd() to scsipi_request(), making sure we call scsipi_done
even in polled case, and doing the adjustments for struct name changes
is enouth to get a HBA driver working again. Using all features of the
new mid layer isn't required :)

One improvement I can see to the midlayer is handling SENSE conditions from
here. From the HBA pow, a request sense is a command like others, and the
mid layer could just pass a scsipi_xfer for the request sense command.
This would make HBA drivers even more simple (currently we need to build
the request sense command, have a recursive call, and separate bus_dma maps
for the sense data in the HBA driver). This should be quite easy to do.

Comments ? Any other feature that would be usefull at the mid-layer level ?

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--