scsi_target experiences and questions

John Linwood Griffin griffin2+freebsd-scsi at ece.cmu.edu
Sat Dec 27 09:06:16 PST 2003


Greetings to all,

In regards the scsi_target code, I'd like to share some experiences and
ask a few questions.

I've been working with scsi_target with FreeBSD 4.8-R and 5.1-R targets
and mostly Linux 2.4.[18,20] initiators, using both Fibre Channel
(Qlogic QLA2100) and Parallel SCSI (Adaptec 29160) connections.

First, the experiences:

1) Chuck Tuffli wrote to this list in August about having trouble using
   anything but LUN "0" when configuring a Qlogic card in target mode.
   (The specific error was "enable lun CCB rejected, status 0x39".)  I
   had this problem also, and it seemed to disappear after I enabled the
   card's BIOS in the Alt-Q setup utility.  Also in the BIOS, I set the
   execution throttle to 255, because 256 was incorrectly read as "0"
   during system boot.

2) I had a problem that the cam/scsi/scsi_target kernel code wouldn't
   shut down cleanly: The TARGIOCDISABLE call would never return, and
   the system had to be reboot between emulator invocations.  I tracked
   this down to the "tsleep()" (msleep() in 5.1?) that immediately
   follows the comment "If we aborted at least one pending CCB ok, wait
   for it."  I commented out the tsleep() call, which appears to allow
   it to be cleanly shut down and restarted multiple times.  (Perhaps
   that's causing some kernel state to not get cleaned up?)  This was
   using the fibre channel card -- I haven't tested whether the problem
   exists using parallel SCSI.

3) I had to disable the "pending unit attention" that is set to indicate
   the device's "powering on".  (I.e., I commented out the line
   "istate->pending_ua = UA_POWER_ON" in scsi_cmds.c.)  This was because
   a FreeBSD initiator wasn't correctly handling the CHECK CONDITION
   status received during the READ CAPACITY command, and instead tried
   reading an invalid geometry.  (This was also only tested with fibre
   channel.  Also, it was before I tried enabling autosense, which may
   fix the problem.)  Without this comment, the device was seen as:

   da1: <FreeBSD Emulated Disk 0.1> Fixed Direct Access SCSI-3 device
   da1: 100.000MB/s transfers
   da1: 0MB (268784067 0 byte sectors: 0H 0S/T 0C)

   Once the comment was in place, it was correctly read as:

   da1: <FreeBSD Emulated Disk 0.1> Fixed Direct Access SCSI-3 device
   da1: 100.000MB/s transfers
   da1: 20MB (40960 512 byte sectors: 64H 32S/T 20C)

4) This isn't specifically related to the scsi_target code, but I was
   surprised to find that the AIO code has a race condition: if you
   aio_write block X, then immediately synchronously read block X before
   the AIO code commits the written block to disk, you'll get the old
   version of X during the read.  I worked around this by always doing
   synchronous writes.

5) Kudos to Nate Lawson and Justin Gibbs for all their good work.  I
   recommend that Nate add a "FAQ" section to his scsi_target page with
   some of the other relevant goodies that have been posted to this list
   (for example, Kenneth Merry posted some gems about enabling autosense
   and increasing MAX_INITIATORS); that would aid in us users getting
   working systems more quickly.

6) I think I've finally figured out the execution path for READ and
   WRITE requests through the scsi_target.c and scsi_cmds.c files.  Nate
   is either an unparalleled genius (for getting it to work in the first
   place) or a diabolical masochist (for knowing that the rest of us
   would tear our hair out following his multiple re-entries into the
   tcmd_handle() function).

   Going off the top of my head, here are a few pointers for anyone else
   digging through the code.  (Note that I may be wrong in places.)
   "ATIO" stands for "Accept Target I/O".  At startup, the user code
   allocates space for a bunch of ATIOs and gives them to the kernel.
   When new requests arrive on the SCSI bus, the kernel sends one of
   these ATIOs back to the user.  "CTIO" stands for "Continue Target
   I/O".  CTIOs are used to transfer data between the user and kernel
   processes.  This is necessary because each CTIO can only handle
   DFLTPHYS (or maybe MAXPHYS) amount of data, but SCSI requests can be
   larger than that.  Once the request is done processing, the user code
   sends the ATIO back to the kernel for reuse.  The user signals that a
   READ request is complete [i.e., then the kernel code is permitted to
   finish the bus transaction] by sending the final CTIO, and it signals
   that a WRITE request is complete by sending the final ATIO.

   I found it very useful to print out function names (as well as ATIO
   and CTIO pointers) as functions were entered; this greatly helped my
   understanding of how READ and WRITE requests were processed.

Now, for a few questions:

A) How difficult will it be to add tagged queuing support to the Adaptec
   driver?  (Or, is the missing piece simply support in the scsi_target
   user code?)  I would find this capability extremely useful.

B) I've been having a maddening problem using tagged queuing with fibre
   channel.  When the system is under high write load (e.g., if I am
   emulating a large disk and I run mkfs over the disk) the scsi_target
   will crash in a seemingly nondeterministic way.  (Note, I am using a
   modified version of scsi_target, but I haven't changed its core
   behavior.)  Sometimes an ATIO is received with its flags field set to
   zero (causing work_atio() to abort) -- this would seem to indicate
   that the ATIO were sent before the data were received from the
   initiator, but this seems impossible based on my cursory look over
   the Qlogic driver code.  Other times I start getting a series of
   error messages on the console [it may be the "no ATIO2s for lun 0
   from initiator 3" message, but I'm not certain -- I can reproduce the
   exact message if it will help this debugging] but I don't think it's
   run out of ATIOs, because I increased the number to 1024 and there
   were only about ten outstanding requests at the time.

   My best guesses are that because of the high write load some kernel
   structures are getting overwritten, or linked lists of free/allocated
   ATIOs in the kernel are being improperly managed, but the answer is
   so far eluding me.  A colleague suggested it may be mishandling of
   tagged requests by the XPT code, but that seems unlikely.  Does
   anyone have any idea what might be causing this, or what a solution
   might be (other than rate-limiting the initiator)?


More information about the freebsd-scsi mailing list