Edward Pilatowicz wrote:
> will the /devices/ paths for blk2scsa devices use generic names
> or will the /devices paths contain driver names?
>
> an example of a generic name (for a usb disk device) is:
> /devices/pci at 0,0/pci104d,81e6 at 1d,7/storage at 3/disk at 0,0:g
>
> an example of a non-generic name (for an ata disk device) is:
> /devices/pci at 0,0/pci-ide at 1f,2/ide at 0/cmdk at 0,0:h
>
The portion of the path that blk2scsa controls will use generic
names. Actually, I'm using scsi_hba_nodename_compatible_get() to
generate both the nodename and the compatible names. (Originally I
started out with just "disk" for the node name and "sd" for the
compatible name hardcoded, but a comment from Joerg Schilling convinced
me that it might be better to offer the other SCSI bindings so that
folks could associate a driver other than "sd" with a blk2scsa device if
they really wanted to.)
-- Garrett
> ed
>
> On Tue, Nov 27, 2007 at 12:50:09AM -0800, Garrett D'Amore wrote:
>
>> I've found in the course of trying to add support for hotplug properly
>> to the blk2scsa driver, that some changes to the API were necessary.
>> While here, I made some other aesthetic changes which are easy to do
>> now, but would require more annoying casework later.
>>
>> A full updated spec is attached.
>>
>> The main differences here relative to the first spec are:
>>
>> * b2s_hba renamed to b2s_nexus
>> * b2s_target renamed to b2s_leaf
>> * structure passed for nexus allocation, instead of array of pointers
>> * request entry point associated with nexus structure instead of leaf
>> * addition of target and lun members to request structure
>> * support for non-zero lun numbers (multiple luns per target)
>> * inquiry data now handled via separate request command, rather than at
>> registration
>> * no separate allocation/deallocation for leaf structure, done by leaf
>> attach/detach automatically (possibly deferred for hotplug safety).
>>
>> I'm extending the case timer another week to allow for the extra review
>> required. Sorry, for the late changes, but thanks!
>>
>>
>> Generic Block Device to SCSA Translation Layer
>> Functional Specification
>>
>> Garrett D'Amore (gdamore at sun.com)
>> Nov 27, 2007
>>
>>
>> CHAPTER 1: Introduction
>>
>> There are an ever growing number of digital memory formats, as well as
>> other kinds of storage media in the market today. Historically, Solaris
>> has had only limited support for most of them, when connected through a
>> USB or IEEE 1394 media reader.
>>
>> Modern laptops and mobile computing devices are now shipping with slots
>> for these readers that are not connected via USB interfaces. Solaris needs
>> needs to provide support for media in these slots in a manner similar to
>> how they are presented via USB.
>>
>> Writing a full block device driver is one possible way, but, unfortunately,
>> it also means implementing a number of components besides the block
>> driver itself, as various userland components exist (such as libsmedia)
>> which only know how to talk to certain block devices.
>>
>> The sd(7d) device driver is the most common mass storage block driver, and
>> it is also how most removable media is presented to the system. Therefore,
>> it already has most of the hooks necessary to support userland volume
>> management, format and VTOC management, etc.
>>
>> Unfortunately, sd(7d) expects to be able to talk to a SCSI disk. Busses
>> such as USB and IEEE1394 often present mass storage using some subset of
>> the SCSI command set, so combined with thin translation layers such as
>> scsa1394 or scsa2usb, it is possible to emulate a SCSI bus sufficiently
>> that these mass storage devices are usable with sd(7d).
>>
>> Many of the intersting media formats, however, do not use any form of SCSI
>> command set. Sometimes the access method is quite different, even though
>> the underlying media is still typically block-oriented.
>>
>>
>> CHAPTER 2: blk2scsa translation layer
>>
>> Our solution to this problem involves the creation of a new kernel/misc
>> module, blk2scsa. This module provides some straight-forward underlying
>> APIs for block-oriented drivers to implement, and maps those APIs to an
>> emulated SCSI bus and one or more emulated SCSI disk drives, so that these
>> devices are now usable with sd(7d).
>>
>> This frees the block device driver from needing to implement most of the
>> labeling, ioctl, or other complex portions of the block device and instead
>> focus on just the core device access functionality.
>>
>> In a sample system, imagine a block device driver called "nvflash". This
>> device driver has two independent flash chips per instance, each of which
>> is block oriented using 512 byte blocks, and can have a separate filesystem
>> on it. The plumbing might look like this:
>>
>>
>> +----------+
>> | nvflash |
>> | driver |
>> | +----------+ +----------------+ +--------------+
>> +----+ blk2scsa |----> | (emulated bus) | -+---> | sd, target 0 |
>> +----------+ +----------------+ | +--------------+
>> |
>> | +--------------+
>> +---> | sd, target 1 |
>> +--------------+
>>
>> In the diagram above, the flash chips would be addressable as
>> /dev/{rdsk,dsk}/cXt0d0 and /dev/{rdsk,dsk}/cXt1d0.
>>
>> Note that the actual flash chips could be removable (perhaps as if they
>> were slots on a physical media reader), and the sd driver would handle
>> them properly. This would include automatic volume manager support
>> by userland components, so that when a device is inserted it is
>> automatically
>> mounted and presented in a desktop GNOME session, for example.
>>
>> The emulated HBA will support auto-sense-request (cannot be disabled),
>> and emulated targets will support the removable and hotpluggable properties
>> if they were registered with them.
>>
>>
>> CHAPTER 3: Programming Interface
>> =================================
>>
>> The following API is provided for target devices.
>>
>> Basic setup
>> -----------
>>
>> The device driver shall #include <sys/scsi/adapters/blk2scsa.h>
>>
>> The device driver shall add -N misc/blk2scsa to its link line, so
>> that the run-time kernel loader can resolve the sybmols
>> appropriately.
>>
>>
>> Types
>> -----
>>
>> typedef struct b2s_nexus b2s_nexus_t;
>>
>> The b2s_nexus_t structure is an opaque structure that is used as a handle
>> to the emulated host bus adapter.
>>
>> typedef struct b2s_leaf b2s_leaf_t;
>>
>> The b2s_leaf_t structure is an opaque structure that is used as a handle
>> to the emulated disk device.
>>
>> typedef struct b2s_nexus_info b2s_nexus_info_t;
>>
>> The b2s_nexus_info structure describes the nexus device that should be
>> allocated. It has the following members:
>>
>> int nexus_version;
>> dev_info_t *nexus_dip;
>> void *nexus_private;
>> ddi_dma_attr_t *nexus_dma_attr;
>> boolean_t (*nexus_request)(void *, struct b2s_request *);
>>
>> The nexus_version field is used for versioning, and represents the version
>> of the API that the device driver is coded for. It must be B2S_VERSION_0
>> in this specification.
>>
>> The nexus_dip is the device node associated with the driver.
>>
>> The nexus_private field is available for the device driver's own
>> use, and should point to nexus state.
>>
>> The nexus_dma_attr is the DMA attributes describing the DMA
>> capabilities of
>> the driver. It may be NULL if the driver is incapable of DMA.
>>
>> The nexus_request field is the entry point that the device driver
>> implements
>> to handle I/O requests. It is passed nexus_private as its first argument.
>> The second argument describes the request in further detail. If the
>> driver
>> handles the request (or queues it for handling), then it must return
>> B_TRUE. If the driver is unwilling to accept the request, but a future
>> attempt might be successful, then it should return B_FALSE. Please see
>> the description for b2s_request_t below.
>>
>> typedef b2s_leaf_info b2s_leaf_info_t;
>>
>> The b2s_leaf_info structure describes a leaf device (emulated SCSI
>> disk) that should be attached to the system. It has the following
>> members:
>>
>> uint_t leaf_target;
>> uint_t leaf_lun;
>> uint32_t leaf_flags;
>> const char *leaf_unique_id;
>>
>> uint32_t target_flags;
>> boolean_t (*target_request)(void *, struct b2s_request *);
>>
>> The leaf_target and leaf_lun fields are target and lun numbers to
>> use for the emulated SCSI target. (For example, the disk device node
>> /dev/dsk/cXtYdZs2, the leaf_target is represented by Y, and the leaf_lun
>> is represented by Z.) The combination of these two fields must be unique
>> for a given leaf node.
>>
>> The leaf_unique_id field is an ASCIIZ string containing a string that
>> uniquely identifies the device. The system uses this to protect against
>> incorrect hotplug operations. (I.e. insertion of a different leaf target
>> at the specified SCSI address, while the previous leaf was still open
>> by another consumer.) It may be used in the formulation of device
>> identifiers and GUIDs as well.
>>
>> The leaf_flags field can contain one of two flags:
>>
>> B2S_LEAF_REMOVABLE - indicates that the leaf supports removable
>> media
>>
>> B2S_LEAF_HOTPLUGGABLE - indicates that the leaf can be hot
>> plugged (including either removal or attachment.)
>>
>> typedef struct b2s_request b2s_request_t;
>>
>> This structure is the fundamental handle used for tracking I/O requests
>> between the SCSA layer and the device driver. It has the following
>> accessible members:
>>
>> int br_cmd;
>> uint64_t br_lba;
>> uint64_t br_nblks;
>> b2s_media_t br_media;
>> b2s_inquiry_t br_inquiry;
>> uint32_t br_flags;
>>
>> The br_cmd field is the command code for the operation. See Commands
>> below for a full explanation. This field is supplied by the blk2scsa.
>>
>> The br_lba field is the logical block address associated with the request.
>> It will be supplied by the blk2scsa framework. It is only valid when the
>> br_cmd field is B2S_CMD_READ or B2S_CMD_WRITE.
>>
>> The br_nblks is the number of logical blocks for the request. It will be
>> supplied by the blk2scsa framework. It is only valid when the br_cmd
>> field
>> is B2S_CMD_READ or B2S_CMD_WRITE.
>>
>> The br_media field is a description of the media for the target. It is
>> filled out by the driver in response to a B2S_CMD_GETMEDIA request.
>> See the description of b2s_media_t below.
>>
>>
>> The br_inquiry field contains inquiry data for the target, to be filled
>> out by the device driver in response to a B2S_CMD_INQUIRY request.
>> See the description of b2s_inquiry_t below.
>>
>> The br_flags field is a bitfield of flags associated the request. The
>> public flags, which are read-only supplied by the framework, are
>>
>> B2S_REQUEST_FLAG_POLL - indicates that a synchronous request without
>> use of interrupts should be performed. (Such as when sync()'ing
>> filesystems or performing a crash dump in response to a panic.)
>>
>> B2S_REQUEST_FLAG_HEAD - indicates that the request should be placed at
>> the head of any queue, if possible.
>>
>> B2S_REQUEST_FLAG_LOAD_EJECT - only valid with the B2S_CMD_STOP or
>> B2S_CMD_START commands, it indicates that the media should either be
>> loaded (B2S_CMD_START) or ejected (B2S_CMD_STOP) if possible.
>>
>> B2S_REQUEST_FLAG_IMMED - if present, indicates that the driver should
>> not wait for the operation to complete on the device before returning
>> status with b2s_request_done(). It is only valid with the commands
>> B2S_CMD_FORMAT, B2S_CMD_START, and B2S_CMD_STOP commands.
>>
>> typedef struct b2s_media b2s_media_t;
>>
>> This structure is used in response to B2S_CMD_GETMEDIA. The device driver
>> shall supply information about the media in the following fields:
>>
>> uint64_t media_blksz;
>> uint64_t media_nblks;
>> uint64_t media_flags;
>>
>> The media_blksz and media_nblks fields are used to report the size and
>> total
>> number of logical blocks on the device.
>>
>> The media_flags bit field can have the flag B2S_MEDIA_FLAG_READ_ONLY
>> set to
>> indicate that the media loaded in the target is not writable.
>>
>> typedef struct b2s_inquiry b2s_inquiry_t;
>>
>> This structure is used in rsponse to B2S_CMD_INQUIRY. The device driver
>> shall set the following fields for data to include in a standard SCSI
>> inquiry:
>>
>> const char *inq_vendor;
>> const char *inq_product;
>> const char *inq_revision;
>> const char *inq_serial;
>>
>> The inq_vendor, inq_product, inq_revision, and inq_serial
>> fields are ASCIIZ strings used to identify the device. Note that this
>> is for the target, and not for any removable media that may be present
>> in the target. These strings are used to formulate the response to
>> SCSI inquiries, so if the device driver is able to, it should use
>> values that are suitable for SCSI-2. (See ANSI X3.131-1994 for more
>> information.) Note that the driver need not pad these strings with
>> spaces.
>>
>>
>> Functions
>> ---------
>>
>> int b2s_mod_init(struct modlinkage *);
>> int b2s_mod_fini(struct modlinkage *);
>>
>> These routines are called at _init and _fini respectively, to set up
>> and clean up HBA related entries in the device driver's dev_ops field.
>> As a consquence, a blk2scsa dependent driver need not supply any cb_ops
>> or bus_ops structure on its own behalf.
>>
>> b2s_nexus_t *b2s_alloc_nexus(b2s_nexus_info_t *);
>>
>> This allocates an initial emulated HBA structure, using the supplied
>> information.
>>
>> void b2s_free_nexus(b2s_nexus_t *);
>>
>> This frees an unattached emulated HBA structure.
>>
>> b2s_leaf_t *b2s_attach_leaf(b2s_nexus_t *, b2s_leaf_info_t *);
>>
>> This indicates that a leaf (disk) device has been physically
>> attached to the nexus (HBA). Appropriate hotplug actions will be
>> performed to make the device accessible, if possible. It returns
>> an opaque handle to the leaf on success, or NULL on failure.
>>
>> void b2s_detach_leaf(b2s_leaf_t *leaf);
>>
>> This indicates that a leaf device has been physically detached from
>> the nexus, and exists solely to support hotplug operation.
>>
>> void b2s_request_mapin(b2s_request_t *req, caddr_t *addrp, size_t *lenp);
>>
>> This ensures that the buffer associated with the request is mapped into
>> kernel address space, and returns the address and length of the buffer
>> associated with the request.
>>
>> void b2s_request_dma(b2s_request_t *req, uint_t *num, ddi_dma_cookie_t **c);
>>
>> This returns the number of DMA cookies associated with the request, and
>> a pointer to an array of the actual cookies. Note that requests are
>> pre-mapped by the framework if a suitable DMA attribute was supplied at
>> registration time. Note also that the buffer will always be fully mapped.
>> That is, it will never be necessary for a driver to use ddi_dma_getwin().
>>
>> void b2s_request_done(b2s_request_t *req, int errno, size_t resid);
>>
>> This is called by the driver when it has completed processing for a
>> request.
>> The errno takes an error code (see Error Codes below), and the resid
>> indicates the number of residual bytes that were not transferred.
>>
>> int b2s_attach_nexus(b2s_nexus_t *);
>>
>> This attaches the HBA (and any registered leaves) to the system. The
>> target driver should call this as part of its attach(9e) processing. It
>> return DDI_SUCCESS on success, DDI_FAILURE otherwise.
>>
>> int b2s_detach_nexus(b2s_nexus_t *);
>>
>> This detaches the HBA from the system. It returns DDI_SUCCESS on success,
>> DDI_FAILURE otherwise.
>>
>>
>> Commands
>> --------
>>
>> B2S_CMD_INQUIRY
>>
>> This command is sent to the driver to retrieve a description of the
>> device in response to a SCSI inquiry. The driver shall provide the
>> details
>> in the br_inquiry field of the associated request.
>>
>> B2S_CMD_GETMEDIA
>>
>> This command is sent to the driver to retrieve a description of the
>> media currently loaded. The driver shall provide the details in the
>> br_media field of the associated request.
>>
>> B2S_CMD_START
>>
>> This command is used to initialize the device for use. If the
>> B2S_REQUEST_FLAG_LOAD_EJECT is also present, then the device shall
>> load any removable media, if possible.
>>
>> B2S_CMD_STOP
>>
>> This command is used to cease use of the device. (At this point the
>> device may be powered down.) If the B2S_REQUEST_FLAG_LOAD_EJECT is
>> present, then the device should attempt to eject any removable media.
>> This command also implictly includes the effects of B2S_CMD_SYNC.
>>
>> B2S_CMD_LOCK
>> B2S_CMD_UNLOCK
>>
>> These commands are used to engage or release any locking mechanism
>> preventing removal of the media.
>>
>> B2S_CMD_READ
>> B2S_CMD_WRITE
>>
>> These commands read or write blocks to/from the device. The block address
>> to start at is indicated by the br_lba field of the request. The number
>> of blocks to transfer is indicated by the br_nblks field. The actual
>> data region can be determined using either the b2s_request_mapin() or
>> b2s_request_dma() functions (depending on whether or not DMA is to be
>> used.)
>>
>> B2S_CMD_FORMAT
>>
>> This command formats the media. It shall not be possible to format media
>> while a reservation set with B2S_CMD_RESERVE is in effect. No defect
>> list is supplied, so the driver is responsible to take whatever action
>> it deems appropriate. If the B2S_REQUEST_FLAG_IMMED is set, then the
>> device should not wait for the format to complete before calling
>> b2s_request_done().
>>
>> B2S_CMD_SYNC
>>
>> This command flushes any cached write data from the device to media.
>>
>>
>> Errors
>> ------
>>
>> The following error codes can be returned in response to a request using
>> b2s_request_done().
>>
>> B2S_EOK
>>
>> No error. The operation completed successfully.
>>
>> B2S_ENOTSUP
>>
>> The device does not support the requested operation. (This should be
>> returned, if the device does not have a door lock, for example.)
>>
>> B2S_EFORMATTING
>>
>> An attempt to access the device while it was formatting was made.
>>
>> B2S_ENOMEDIA
>>
>> No media is present in a target with removable media.
>>
>> B2S_EMEDIACHG
>>
>> The media may have changed since the last request was made. This is
>> used to prevent accidental overwrites to changed media.
>>
>> B2S_ESTOPPED
>>
>> The target has not been started with B2S_CMD_START yet.
>>
>> B2S_EHARDWARE
>>
>> An unknown hardware error occurred.
>>
>> B2S_ENODEV
>>
>> The target is not present or has been removed.
>>
>> B2S_EMEDIA
>>
>> An error on the medium occurred.
>>
>> B2S_EDOORLOCK
>>
>> The B2S_CMD_STOP failed to eject the media, because the doorlock was
>> engaged.
>>
>> B2S_EWPROTECT
>>
>> The media could not be written to because it is not writable.
>>
>> B2S_EBLKADDR
>>
>> The supplied LBA block address was invalid.
>>
>> B2S_ESTARTING
>>
>> The target is still starting up. Try agin later.
>>
>> B2S_EIO
>>
>> Generic failure.
>>
>> B2S_ERSVD
>>
>> Target reserved. (Internal use only.)
>>
>> B2S_EPARM
>>
>> Bad parameter occurred in the SCSI packet. (Internal use only.)
>>
>> B2S_EBADMSG
>>
>> Invalid SCSI message presented to driver. (Internal use only.)
>>
>> B2S_EINVAL
>>
>> An invalid parameter was present in the SCSI packet. (Internal use only.)
>>
>>
>> CHAPER 4: Interface Table
>> ==========================
>>
>> Imported Interface Level Comments
>>
>> SCSI-2 Committed ANSI X1.131-1994
>> scsi_hba_tran Committed SCSI HBA API
>> scsi_pkt2bp() Consolidation Private
>>
>>
>> Exported Interface Level Comments
>>
>> sys/scsi/adapters/blk2scsa.h Cons. Private blk2scsa header
>>
>> misc/blk2scsa Consolidation Private kernel module
>> B2S_CMD_* Consolidation Private request command codes
>> B2S_E* Consolidation Private request error codes
>> B2S_REQUEST_FLAG_* Consolidation Private request flags
>> B2S_VERSION_0 Consolidation Private API versioning
>>
>> struct b2s_request Consolidation Private request structure
>> struct b2s_leaf Consolidation Private leaf (disk) structure (opaque)
>> struct b2s_nexus Consolidation Private nexus (hba) structure
>> (opaque)
>> struct b2s_leaf_info Consolidation Private leaf (disk) attach
>> information
>> struct b2s_nexus_info Consolidation Private nexus (hba) registration
>> struct b2s_media Consolidation Private media description
>> struct b2s_inquiry Consolidation Private SCSI inquiry data
>>
>> b2s_alloc_nexus() Consolidation Private nexus (hba) allocation
>> b2s_free_nexus() Consolidation Private nexus (hba) deallocation
>> b2s_attach_nexus() Consolidation Private nexus (hba) attachment
>> b2s_detach_nexus() Consolidation Private nexus (hba) detachment
>>
>> b2s_attach_leaf() Consolidation Private leaf (disk) connection
>> b2s_detach_leaf() Consolidation Private leaf (disk) disconnection
>>
>> b2s_request_mapin() Consolidation Private request buffer PIO access
>> b2s_request_dma() Consolidation Private request buffer DMA access
>> b2s_request_done() Consolidation Private request buffer completion
>>
>> b2s_mod_init() Consolidation Private modlinkage initialization
>> b2s_mod_fini() Condolidation Private modlinkage de-initialization
>>