(probably due to an interrupt) between the time it is scheduled and the
time we get around to setting the SCSI_ASYNCREQ flag, we can lose the xs.
Fix this by checking to see if the transfer has already completed after
the scsi_cmd function returns SUCCESSFULLY_QUEUED, and just return to the
caller if so.
descriptor count gets miscounted on txprobes. The second (and more
important) is that transmit stalls should now be fixed. The problem
was not due to lack of ring resources but dmamaps. When Jason changed
the driver to use pre-allocated maps (instead of the dynamic ones I
used), and when there were no more maps, the driver just gave up instead
of calling tx_intr to free any transmitted but unreclaimed dma maps.
Since there was nothing being transmitted, no transmit interrupts
would fire to restore things (and OACTIVE prevented other transmits
from happenning). So it stayed starved until another interrupt cause
(like a received packet) "woke" it up.
XXX Actually, libc appears to use only 7 of the previous 10, so increasing
the size isn't actually necessary! But there was a gap at the end before,
so we'll keep it.
use PIO (or equivalent) code to do asynchronous transfers: In
ncr5380_scsi_cmd(), test to see if the request has been completed after
the call to ncr5380_sched(), and return COMPLETE if so. This avoids
going into an infinite loop in scsipi_execute_xs() while waiting for an
interrupt to trigger completion of the transfer... which, of course,
never happens, since it's already done.
scsipi_xfer structures.
When scsipi_execute_xs() calls the driver's scsi_cmd function, it assumes
that it can still dereference a pointer to the scsipi_xfer struct. Since
scsipi_done() has already been called, which in turn has called
scsipi_free_xs(), the struct has already been returned the structure to
the pool! In other words, xs->flags has been compromised, but we are still
testing it.
These changes resolve the problem by doing the following:
- In scsipi_execute_xs(), if the hardware driver's scsi_cmd function
returns SUCCESSFULLY_QUEUED, set a new flag (SCSI_ASYNCREQ) in xs->flags.
Since the request will be handled asynchronously, we will need the
scsipi_xfer struct to be freed in scsipi_done().
If the hardware driver's scsi_cmd function returns COMPLETE, we now
simply return any actual errors, or 0 if none occurred. (Previously,
we may have returned EJUSTRETURN, of which the sole effect was to
avoid freeing the scsipi_xfer struct in our caller.)
- In scsipi_done(), only free the scsipi_xfer struct for async requests.
The contents of the struct will otherwise remain valid until the
function that initiated the transfer frees it.
With this change, responsibility for freeing the struct now lies in two
places, depending on the type of the request:
- For synchronous requests, the routine calling scsipi_execute_xs()
must clean up.
- For asynchronous requests, scsipi_done() cleans up (as it always has).
[Note: this change also corrects a problem with sddump(): scsipi_done()
was attempting to return a static scsipi_xfer struct to the pool! Since
dumps are performed synchronously, we now handle this correctly.]
This solution was provided by Jason Thorpe, after I got him to look at
some related (but insufficient) attempts of my own.
scsipi_xfer structures.
When scsipi_execute_xs() calls the driver's scsi_cmd function, it assumes
that it can still dereference a pointer to the scsipi_xfer struct. Since
scsipi_done() has already been called, which in turn has called
scsipi_free_xs(), the struct has already been returned to the pool! In
other words, xs->flags has been compromised, but we are still testing it.
These changes resolve the problem by doing the following:
- In scsipi_execute_xs(), if the lower-level driver's scsi_cmd function
returns SUCCESSFULLY_QUEUED and SCSI_NOSLEEP is set in xs->flags, set a
new flag (SCSI_ASYNCREQ). This indicates that scsipi_done() should free
the scsipi_xfer struct.
If the lower-level driver's scsi_cmd function returns SUCCESSFULLY_QUEUED
but SCSI_NOSLEEP is not set, we wait (via tsleep()) for the request to
complete, then fall through to the COMPLETE case.
If the lower-level driver's scsi_cmd function returns COMPLETE, we now
simply return any actual errors, or 0 if none occurred. (Previously,
we may have returned EJUSTRETURN, of which the sole effect was to
avoid freeing the scsipi_xfer struct in our caller. No code seems
to depend on this behavior, however.)
- In scsipi_done(), only free the scsipi_xfer struct for async requests.
The contents of the struct will otherwise remain valid until the
function that initiated the transfer frees it.
With this change, responsibility for freeing the struct now lies in two
places, depending on the type of the request:
- For synchronous requests, the routine calling scsipi_execute_xs()
must clean up.
- For asynchronous requests, scsipi_done() cleans up (as it always has).
[Note: this change also corrects a problem with sddump(): scsipi_done()
was attempting to return a static scsipi_xfer struct to the pool! Since
dumps are performed synchronously, we now handle this correctly.]
This solution was provided by Jason Thorpe, after I got him to look at
some related (but insufficient) attempts of my own.
signal mask since a 1.3 binary may attempt to invoke sigreturn(2) directly
for an alternate exit from the signal handler. If we don't do this, it will
get a garbage signal mask if it tries to do that.
that sc_ad.ioh is the 8-byte region as opposed to blindly passing it
the first region.
With this change, and a device def which will follow, the IDE controller
on my OPTi Audio 16 card works!