/*
*
* skd.c: Solaris 11/10 Driver for sTec, Inc. S112x PCIe SSD card
*
* Solaris driver is based on the Linux driver authored by:
*
* Authors/Alphabetical: Dragan Stancevic <dstancevic@stec-inc.com>
* Gordon Waidhofer <gwaidhofer@stec-inc.com>
* John Hamilton <jhamilton@stec-inc.com>
*/
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* Copyright 2013 STEC, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <sys/dditypes.h>
#include "skd_s1120.h"
#include "skd.h"
int skd_dbg_level = 0;
int skd_disable_msi = 0;
int skd_disable_msix = 0;
/* Initialized in _init() and tunable, see _init(). */
/* I/O DMA attributes structures. */
DMA_ATTR_V0, /* dma_attr_version */
SKD_DMA_LOW_ADDRESS, /* low DMA address range */
SKD_DMA_HIGH_64BIT_ADDRESS, /* high DMA address range */
SKD_DMA_XFER_COUNTER, /* DMA counter register */
SKD_DMA_ADDRESS_ALIGNMENT, /* DMA address alignment */
SKD_DMA_BURSTSIZES, /* DMA burstsizes */
SKD_DMA_MIN_XFER_SIZE, /* min effective DMA size */
SKD_DMA_MAX_XFER_SIZE, /* max DMA xfer size */
SKD_DMA_SEGMENT_BOUNDARY, /* segment boundary */
SKD_DMA_SG_LIST_LENGTH, /* s/g list length */
SKD_DMA_GRANULARITY, /* granularity of device */
SKD_DMA_XFER_FLAGS /* DMA transfer flags */
};
static int skd_sys_quiesce_dev(dev_info_t *);
static int skd_quiesce_dev(skd_device_t *);
static int skd_list_skmsg(skd_device_t *, int);
static int skd_list_skreq(skd_device_t *, int);
static void skd_start(skd_device_t *);
static void skd_enable_interrupts(struct skd_device *);
static void skd_send_internal_skspcl(struct skd_device *,
struct skd_special_context *, uint8_t);
int, int);
NULL, /* sync_cache */
};
};
/*
*/
DEVO_REV, /* devo_rev */
0, /* refcnt */
ddi_no_info, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
skd_attach, /* attach */
skd_detach, /* detach */
nodev, /* reset */
NULL, /* bus operations */
NULL, /* power management */
skd_sys_quiesce_dev /* quiesce */
};
&mod_driverops, /* type of module: driver */
&skd_dev_ops /* driver dev_ops */
};
&modldrv,
};
/*
* sTec-required wrapper for debug printing.
*/
/*PRINTFLIKE2*/
static inline void
{
if (skd_dbg_level == 0)
return;
}
/*
*/
/*
*
* Name: _init, performs initial installation
*
* Inputs: None.
*
* Returns: Returns the value returned by the ddi_softstate_init function
* on a failure to create the device state structure or the result
* of the module install routines.
*
*/
int
_init(void)
{
int rval = 0;
int tgts = 0;
tgts |= 0x02;
/*
* drv_usectohz() is a function, so can't initialize it at
* instantiation.
*/
"<# Installing skd Driver dbg-lvl=%d %s %x>",
if (rval != DDI_SUCCESS)
return (rval);
if (rval != DDI_SUCCESS) {
}
return (rval);
}
/*
*
* Name: _info, returns information about loadable module.
*
* Inputs: modinfo, pointer to module information structure.
*
* Returns: Value returned by mod_info().
*
*/
int
{
}
/*
* _fini Prepares a module for unloading. It is called when the system
* wants to unload a module. If the module determines that it can
* be unloaded, then _fini() returns the value returned by
* mod_remove(). Upon successful return from _fini() no other
* routine in the module will be called before _init() is called.
*
* Inputs: None.
*
* Returns: DDI_SUCCESS or DDI_FAILURE.
*
*/
int
_fini(void)
{
int rval;
if (rval == DDI_SUCCESS) {
}
return (rval);
}
/*
*/
/*
*
* Name: skd_reg_write64, writes a 64-bit value to specified address
*
* Inputs: skdev - device state structure.
* val - 64-bit value to be written.
* offset - offset from PCI base address.
*
* Returns: Nothing.
*
*/
/*
* Local vars are to keep lint silent. Any compiler worth its weight will
* optimize it all right out...
*/
static inline void
{
/* LINTED */
}
/*
*
* Name: skd_reg_read32, reads a 32-bit value to specified address
*
* Inputs: skdev - device state structure.
* offset - offset from PCI base address.
*
* Returns: val, 32-bit value read from specified PCI address.
*
*/
static inline uint32_t
{
/* LINTED */
}
/*
*
* Name: skd_reg_write32, writes a 32-bit value to specified address
*
* Inputs: skdev - device state structure.
* val - value to be written.
* offset - offset from PCI base address.
*
* Returns: Nothing.
*
*/
static inline void
{
/* LINTED */
}
/*
* Solaris skd routines
*/
/*
*
* Name: skd_name, generates the name of the driver.
*
* Inputs: skdev - device state structure
*
* Returns: char pointer to generated driver name.
*
*/
static const char *
{
}
/*
*
* Name: skd_pci_find_capability, searches the PCI capability
* list for the specified capability.
*
* Inputs: skdev - device state structure.
* cap - capability sought.
*
* Returns: Returns position where capability was found.
* If not found, returns zero.
*
*/
static int
{
if (!(status & PCI_STAT_CAP))
return (0);
if ((hdr & PCI_HEADER_TYPE_M) != 0)
return (0);
pos &= ~3;
if (id == 0xff)
break;
return (pos);
}
return (0);
}
/*
*
* Name: skd_io_done, called to conclude an I/O operation.
*
* Inputs: skdev - device state structure.
* pbuf - I/O request
* error - contain error value.
* mode - debug only.
*
* Returns: Nothing.
*
*/
static void
{
switch (mode) {
case SKD_IODONE_WIOC:
skdev->iodone_wioc++;
break;
case SKD_IODONE_WNIOC:
skdev->iodone_wnioc++;
break;
case SKD_IODONE_WDEBUG:
skdev->iodone_wdebug++;
break;
default:
skdev->iodone_unknown++;
}
if (error) {
skdev->ios_errors++;
}
}
/*
* QUIESCE DEVICE
*/
/*
*
* Name: skd_sys_quiesce_dev, quiets the device
*
* Inputs: dip - dev info strucuture
*
* Returns: Zero.
*
*/
static int
{
/* make sure Dcmn_err() doesn't actually print anything */
skd_dbg_level = 0;
return (0);
}
/*
*
* Name: skd_quiesce_dev, quiets the device, but doesn't really do much.
*
* Inputs: skdev - Device state.
*
* Returns: -EINVAL if device is not in proper state otherwise
* returns zero.
*
*/
static int
{
int rc = 0;
if (skd_dbg_level)
case SKD_DRVR_STATE_BUSY:
break;
case SKD_DRVR_STATE_ONLINE:
case SKD_DRVR_STATE_STOPPING:
case SKD_DRVR_STATE_SYNCING:
case SKD_DRVR_STATE_PAUSING:
case SKD_DRVR_STATE_PAUSED:
case SKD_DRVR_STATE_STARTING:
case SKD_DRVR_STATE_RESUMING:
default:
}
return (rc);
}
/*
* UNQUIESCE DEVICE:
* Note: Assumes lock is held to protect device state.
*/
/*
*
* Name: skd_unquiesce_dev, awkens the device
*
* Inputs: skdev - Device state.
*
* Returns: -EINVAL if device is not in proper state otherwise
* returns zero.
*
*/
static int
{
return (0);
}
/*
* If there has been an state change to other than
* ONLINE, we will rely on controller state change
* to come back online and restart the queue.
* The BUSY state means that driver is ready to
* continue normal processing but waiting for controller
* to become available.
*/
return (0);
}
/*
* Drive just come online, driver is either in startup,
* paused performing a task, or bust waiting for hardware.
*/
case SKD_DRVR_STATE_PAUSED:
case SKD_DRVR_STATE_BUSY:
case SKD_DRVR_STATE_STARTING:
case SKD_DRVR_STATE_FAULT:
case SKD_DRVR_STATE_IDLE:
case SKD_DRVR_STATE_LOAD:
"%s: queue depth limit=%d hard=%d soft=%d lowat=%d",
break;
default:
return (-EBUSY);
}
return (0);
}
/*
*/
/*
*
* Name: skd_blkdev_preop_sg_list, builds the S/G list from info
* passed in by the blkdev driver.
*
* Inputs: skdev - device state structure.
* skreq - request structure.
* sg_byte_count - data transfer byte count.
*
* Returns: Nothing.
*
*/
/*ARGSUSED*/
static void
{
int i, bcount = 0;
*sg_byte_count = 0;
skreq->total_sg_bcount = 0;
for (i = 0; i < n_sg; i++) {
*sg_byte_count += cnt;
if ((i + 1) != n_sg)
}
}
/*
*
* Name: skd_blkdev_postop_sg_list, deallocates DMA
*
* Inputs: skdev - device state structure.
* skreq - skreq data structure.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static void
struct skd_request_context *skreq)
{
/*
* restore the next ptr for next IO request so we
* don't have to set it every time.
*/
}
/*
*
* Name: skd_start, initiates an I/O.
*
* Inputs: skdev - device state structure.
*
* Returns: EAGAIN if devicfe is not ONLINE.
* On error, if the caller is the blkdev driver, return
* the error value. Otherwise, return zero.
*
*/
/* Upstream common source with other platforms. */
static void
{
int bcount;
void *cmd_ptr;
/*
* Stop conditions:
* - There are no more native requests
* - There are already the maximum number of requests is progress
* - There are no more skd_request_context entries
* - There are no more FIT msg buffers
*/
for (;;) {
/* Are too many requests already in progress? */
break;
}
if (SIMPLEQ_EMPTY(waitq)) {
break;
}
/* Is a skd_request_context available? */
break;
}
/* Start a new FIT msg if there is none in progress. */
/* Are there any FIT msg buffers available? */
break;
}
/* Initialize the FIT msg header */
}
/*
* At this point we are committed to either start or reject
* the native request. Note that a FIT msg may have just been
* started but contains no SoFIT requests yet.
* Now - dequeue pbuf.
*/
skreq->did_complete = 0;
"pbuf=%p lba=%u(0x%x) count=%u(0x%x) dir=%x\n",
/*
* Transcode the request.
*/
} else {
}
"skd_start: pbuf=%p skreq->id=%x opc=%x ====>>>>>",
/*
* Update the active request counts.
* Capture the timeout timestamp.
*/
/*
* If the FIT msg buffer is full send it.
*/
skdev->fitmsg_sent1++;
}
}
/*
* Is a FIT msg in progress? If it is empty put the buffer back
* on the free list. If it is non-empty send what we got.
* This minimizes latency when there are fewer requests than
* what fits in a FIT msg.
*/
skdev->active_cmds++;
skdev->fitmsg_sent2++;
}
}
/*
*
* Name: skd_end_request
*
* Inputs: skdev - device state structure.
* skreq - request structure.
* error - I/O error value.
*
* Returns: Nothing.
*
*/
static void
{
skdev->ios_completed++;
}
/*
*
* Name: skd_end_request_abnormal
*
* Inputs: skdev - device state structure.
* pbuf - I/O request.
* error - I/O error value.
* mode - debug
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_request_fn_not_online, handles the condition
* of the device not being online.
*
* Inputs: skdev - device state structure.
*
* Returns: nothing (void).
*
*/
static void
{
int error;
case SKD_DRVR_STATE_PAUSING:
case SKD_DRVR_STATE_PAUSED:
case SKD_DRVR_STATE_STARTING:
case SKD_DRVR_STATE_WAIT_BOOT:
/*
* In case of starting, we haven't started the queue,
* so we can't get here... but requests are
* possibly hanging out waiting for us because we
* forever if connect doesn't complete.
*/
case SKD_DRVR_STATE_BUSY:
return;
case SKD_DRVR_STATE_STOPPING:
case SKD_DRVR_STATE_SYNCING:
case SKD_DRVR_STATE_FAULT:
default:
break;
}
/*
* If we get here, terminate all pending block requeusts
* with EIO and any scsi pass thru with appropriate sense
*/
return;
}
/*
* TIMER
*/
/*
*
* Name: skd_timer_tick, monitors requests for timeouts.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
goto timer_func_out;
}
skdev->timeout_stamp++;
/*
* All requests that happened during the previous use of
* this slot should be done by now. The previous use was
* over 7 seconds ago.
*/
goto timer_func_out;
}
/* Something is overdue */
skdev->timer_active = 0;
}
/*
*
* Name: skd_timer_tick_not_online, handles various device
* state transitions.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
case SKD_DRVR_STATE_IDLE:
case SKD_DRVR_STATE_LOAD:
break;
break;
case SKD_DRVR_STATE_BUSY:
if (skdev->timer_countdown > 0) {
skdev->timer_countdown--;
return;
}
break;
case SKD_DRVR_STATE_WAIT_BOOT:
case SKD_DRVR_STATE_STARTING:
if (skdev->timer_countdown > 0) {
skdev->timer_countdown--;
return;
}
/*
* For now, we fault the drive. Could attempt resets to
* revcover at some point.
*/
/* start the queue so we can respond with error to requests */
/* wakeup anyone waiting for startup complete */
break;
case SKD_DRVR_STATE_PAUSING:
case SKD_DRVR_STATE_PAUSED:
break;
"!%s: draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n",
/* if the slot has cleared we can let the I/O continue */
return;
}
if (skdev->timer_countdown > 0) {
skdev->timer_countdown--;
return;
}
break;
if (skdev->timer_countdown > 0) {
skdev->timer_countdown--;
return;
}
/*
* For now, we fault the drive. Could attempt resets to
* revcover at some point.
*/
/*
* Recovering does two things:
* 1. completes IO with error
* 2. reclaims dma resources
* When is it safe to recover requests?
* - if the drive state is faulted
* - if the state is still soft reset after out timeout
* - if the drive registers are dead (state = FF)
*/
/*
* It never came out of soft reset. Try to
* recover the requests and then let them
* fail. This is to mitigate hung processes.
*
* Acquire the interrupt lock since these lists are
* manipulated by interrupt handlers.
*/
}
/* start the queue so we can respond with error to requests */
/* wakeup anyone waiting for startup complete */
break;
case SKD_DRVR_STATE_RESUMING:
case SKD_DRVR_STATE_STOPPING:
case SKD_DRVR_STATE_SYNCING:
case SKD_DRVR_STATE_FAULT:
default:
break;
}
}
/*
*
* Name: skd_timer, kicks off the timer processing.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
/* Someone set us to 0, don't bother rescheduling. */
if (skdev->skd_timer_timeout_id != 0) {
/* Pardon the drop-and-then-acquire logic here. */
/* Restart timer, if not being stopped. */
if (skdev->skd_timer_timeout_id != 0) {
}
}
}
/*
*
* Name: skd_start_timer, kicks off the 1-second timer.
*
* Inputs: skdev - device state structure.
*
* Returns: Zero.
*
*/
static void
{
/* Start one second driver timer. */
/*
* Do first "timeout tick" right away, but not in this
* thread.
*/
}
/*
* INTERNAL REQUESTS -- generated by driver itself
*/
/*
*
* Name: skd_format_internal_skspcl, setups the internal
* FIT request message.
*
* Inputs: skdev - device state structure.
*
* Returns: One.
*
*/
static int
{
/* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */
sgd->byte_count = 0;
return (1);
}
/*
*
* Name: skd_send_internal_skspcl, send internal requests to
* the hardware.
*
* Inputs: skdev - device state structure.
* skspcl - request structure
* opcode - just what it says
*
* Returns: Nothing.
*
*/
void
{
/*
* A refresh is already in progress.
* Just wait for it to finish.
*/
return;
}
/* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */
switch (opcode) {
case TEST_UNIT_READY:
sgd->byte_count = 0;
break;
case READ_CAPACITY_EXT:
break;
case 0x28:
break;
case INQUIRY:
break;
case INQUIRY2:
break;
case SYNCHRONIZE_CACHE:
sgd->byte_count = 0;
break;
default:
ASSERT("Don't know what to send");
return;
}
}
/*
*
* Name: skd_refresh_device_data, sends a TUR command.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_complete_internal, handles the completion of
* driver-initiated I/O requests.
*
* Inputs: skdev - device state structure.
* skcomp - completion structure.
* skerr - error structure.
* skspcl - request structure.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static void
volatile struct fit_completion_entry_v1 *skcomp,
volatile struct fit_comp_error_info *skerr,
struct skd_special_context *skspcl)
{
/* Instead of 64-bytes in, use 8-(64-bit-words) for linted alignment. */
case TEST_UNIT_READY:
if (SAM_STAT_GOOD == status) {
} else {
"!%s: TUR failed, don't send anymore"
return;
}
}
break;
case READ_CAPACITY_EXT: {
skdev->read_cap_is_valid = 0;
if (SAM_STAT_GOOD == status) {
cap >> 30ULL);
} else {
}
break;
}
case INQUIRY:
skdev->inquiry_is_valid = 0;
if (SAM_STAT_GOOD == status) {
} else {
}
}
if (skd_unquiesce_dev(skdev) < 0)
break;
case SYNCHRONIZE_CACHE:
break;
default:
ASSERT("we didn't send this");
}
}
/*
* FIT MESSAGES
*/
/*
*
* Name: skd_send_fitmsg, send a FIT message to the hardware.
*
* Inputs: skdev - device state structure.
* skmsg - FIT message structure.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static void
struct skd_fitmsg_context *skmsg)
{
int i;
"%02x %02x %02x %02x",
if (i == 0) i = 64 - 8;
}
}
}
skdev->ios_started++;
}
/*
*
* Name: skd_send_special_fitmsg, send a special FIT message
* to the hardware used driver-originated I/O requests.
*
* Inputs: skdev - device state structure.
* skspcl - skspcl structure.
*
* Returns: Nothing.
*
*/
static void
struct skd_special_context *skspcl)
{
int i;
for (i = 0; i < SKD_N_SPECIAL_FITMSG_BYTES; i += 8) {
" spcl[%2d] %02x %02x %02x %02x "
"%02x %02x %02x %02x\n", i,
if (i == 0) i = 64 - 8;
}
}
}
/*
* Special FIT msgs are always 128 bytes: a 64-byte FIT hdr
* and one 64-byte SSDI command.
*/
}
/*
* COMPLETION QUEUE
*/
volatile struct fit_completion_entry_v1 *skcomp,
volatile struct fit_comp_error_info *skerr);
struct sns_info {
};
/* Good */
/* Smart alerts */
/* Retry (with limits) */
/* Busy (or about to be) */
};
/*
*
* Name: skd_check_status, checks the return status from a
* completed I/O request.
*
* Inputs: skdev - device state structure.
* cmp_status - SCSI status byte.
* skerr - the error data structure.
*
* Returns: Depending on the error condition, return the action
* to be taken as specified in the skd_chkstat_table.
* If no corresponding value is found in the table
* return SKD_CHECK_STATUS_REPORT_GOOD is no error otherwise
* return SKD_CHECK_STATUS_REPORT_ERROR.
*
*/
static enum skd_check_status_action
volatile struct fit_comp_error_info *skerr)
{
/*
* Look up status and sense data to decide how to handle the error
* from the device.
* mask says which fields must match e.g., mask=0x18 means check
* type and stat, ignore key, asc, ascq.
*/
int i, n;
/* Does the info match an entry in the good category? */
n = sizeof (skd_chkstat_table) / sizeof (skd_chkstat_table[0]);
for (i = 0; i < n; i++) {
" %02x/%02x/%02x",
}
}
/*
* No other match, so nonzero status means error,
* zero status means good
*/
if (cmp_status) {
"!%s: status check: qdepth=%d skmfl=%p (%d) skrfl=%p (%d)",
return (SKD_CHECK_STATUS_REPORT_ERROR);
}
return (SKD_CHECK_STATUS_REPORT_GOOD);
}
/*
*
* Name: skd_isr_completion_posted, handles I/O completions.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
for (;;) {
"cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d "
"qdepth_busy=%d rbytes=0x%x proto=%d",
break;
}
/*
* Update the completion queue head index and possibly
* the completion cycle count.
*/
}
/*
* The command context is a unique 32-bit ID. The low order
* bits help locate the request. The request is usually a
* r/w request (see skd_start() above) or a special request.
*/
"<<<< completion_posted 1: req_id=%x req_slot=%x",
/* Is this other than a r/w request? */
/*
* This is not a completion for a r/w request.
*/
continue;
}
/*
* Make sure the request ID for the slot matches.
*/
/*
* a previously timed out command can
* now be cleaned up
*/
skmsg->outstanding--;
if (skmsg->outstanding == 0) {
}
}
/*
* Reclaim the skd_request_context
*/
continue;
}
"I/O err: pbuf=%p blkno=%lld (%llx) nbklks=%ld ",
}
if (SAM_STAT_GOOD == cmp_status) {
/* Release DMA resources for the request. */
} else {
break;
(void) skd_quiesce_dev(skdev);
break;
/* FALLTHRU */
/* fall thru to report error */
default:
/*
* Save the entire completion
* and error entries for
* later error interpretation.
*/
break;
}
}
/*
* Reclaim the FIT msg buffer if this is
* the first of the requests it carried to
* be completed. The FIT msg buffer used to
* send this request cannot be reused until
* we are sure the s1120 card has copied
* it to its memory. The FIT msg might have
* contained several requests. As soon as
* any of them are completed we know that
* the entire FIT msg was transferred.
* Only the first completed request will
* match the FIT msg buffer id. The FIT
* msg buffer id is immediately updated.
* When subsequent requests complete the FIT
* msg buffer id won't match, so we know
* quite cheaply that it is already done.
*/
}
/*
* Decrease the number of active requests.
* This also decrements the count in the
* timeout slot.
*/
/*
* Reclaim the skd_request_context
*/
/*
* make sure the lock is held by caller.
*/
(0 == skdev->queue_depth_busy)) {
}
} /* for(;;) */
}
/*
*
* Name: skd_complete_other, handle the completion of a
* non-r/w request.
*
* Inputs: skdev - device state structure.
* skcomp - FIT completion structure.
* skerr - error structure.
*
* Returns: Nothing.
*
*/
static void
volatile struct fit_completion_entry_v1 *skcomp,
volatile struct fit_comp_error_info *skerr)
{
/*
* Based on the request id, determine how to dispatch this completion.
* completion entry. Errors are reported below the switch.
*/
}
/*
*
* Name: skd_reset_skcomp, does what it says, resetting completion
* tables.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
nbytes = sizeof (struct fit_completion_entry_v1) *
if (skdev->skcomp_table)
}
/*
* INTERRUPTS
*/
/*
*
* Name: skd_isr_aif, handles the device interrupts.
*
* Inputs: arg - skdev device state structure.
* intvec - not referenced
*
* Returns: DDI_INTR_CLAIMED if interrupt is handled otherwise
* return DDI_INTR_UNCLAIMED.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static uint_t
{
for (;;) {
/*
* As long as there is an int pending on device, keep
* running loop. When none, get out, but if we've never
* done any processing, call completion handler?
*/
if (ack == 0) {
/*
* No interrupts on device, but run the completion
* processor anyway?
*/
if (rc == DDI_INTR_UNCLAIMED &&
"1: Want isr_comp_posted call");
}
break;
}
if (intstat & FIT_ISH_COMPLETION_POSTED) {
"2: Want isr_comp_posted call");
}
if (intstat & FIT_ISH_FW_STATE_CHANGE) {
return (rc);
}
}
if (intstat & FIT_ISH_MSG_FROM_DEV) {
}
}
}
return (rc);
}
/*
*
* Name: skd_drive_fault, set the drive state to DRV_STATE_FAULT.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_drive_disappeared, set the drive state to DISAPPEARED..
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_isr_fwstate, handles the various device states.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
int prev_driver_state;
switch (skdev->drive_state) {
case FIT_SR_DRIVE_INIT:
break;
}
}
break;
}
break;
case FIT_SR_DRIVE_ONLINE:
}
"%s queue depth limit=%d hard=%d soft=%d lowat=%d",
break;
case FIT_SR_DRIVE_BUSY:
(void) skd_quiesce_dev(skdev);
break;
break;
case FIT_SR_DRIVE_BUSY_ERASE:
break;
case FIT_SR_DRIVE_OFFLINE:
break;
case FIT_SR_DRIVE_SOFT_RESET:
case SKD_DRVR_STATE_STARTING:
break;
default:
break;
}
break;
case FIT_SR_DRIVE_FW_BOOTING:
break;
case FIT_SR_DRIVE_DEGRADED:
case FIT_SR_PCIE_LINK_DOWN:
break;
case FIT_SR_DRIVE_FAULT:
break;
case 0xFF:
break;
default:
/*
* Uknown FW State. Wait for a state we recognize.
*/
break;
}
}
/*
*
* Name: skd_recover_requests, attempts to recover requests.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
int i;
for (i = 0; i < skdev->num_req_context; i++) {
/* Release DMA resources for the request. */
}
if (i > 0) {
}
}
for (i = 0; i < skdev->num_fitmsg_context; i++) {
}
if (i > 0) {
}
}
for (i = 0; i < SKD_N_TIMEOUT_SLOT; i++) {
skdev->timeout_slot[i] = 0;
}
skdev->queue_depth_busy = 0;
}
/*
*
* Name: skd_isr_msg_from_dev, handles a message from the device.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
/*
* ignore any mtd that is an ack for something we didn't send
*/
return;
}
switch (FIT_MXD_TYPE(mfd)) {
case FIT_MTD_FITFW_INIT:
break;
}
break;
case FIT_MTD_GET_CMDQ_DEPTH:
break;
case FIT_MTD_SET_COMPQ_DEPTH:
break;
case FIT_MTD_SET_COMPQ_ADDR:
break;
case FIT_MTD_ARM_QUEUE:
/*
* State should be, or soon will be, FIT_SR_DRIVE_ONLINE.
*/
break;
default:
break;
}
}
/*
*
* Name: skd_disable_interrupts, issues command to disable
* device interrupts.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
/*
* Note that the 1s is written. A 1-bit means
* disable, a 0 means enable.
*/
}
/*
*
* Name: skd_enable_interrupts, issues command to enable
* device interrupts.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
/* unmask interrupts first */
/*
* Note that the compliment of mask is written. A 1-bit means
* disable, a 0 means enable.
*/
}
/*
*
* Name: skd_soft_reset, issues a soft reset to the hardware.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
val |= (FIT_CR_SOFT_RESET);
}
/*
*
* Name: skd_start_device, gets the device going.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
int delay_action = 0;
/* ack all ghost interrupts */
switch (skdev->drive_state) {
case FIT_SR_DRIVE_OFFLINE:
break;
case FIT_SR_DRIVE_FW_BOOTING:
break;
break;
case FIT_SR_DRIVE_BUSY_ERASE:
break;
case FIT_SR_DRIVE_INIT:
case FIT_SR_DRIVE_ONLINE:
break;
case FIT_SR_DRIVE_BUSY:
break;
case FIT_SR_DRIVE_SOFT_RESET:
break;
case FIT_SR_DRIVE_FAULT:
/*
* Fault state is bad...soft reset won't do it...
* Hard reset, maybe, but does it work on device?
* For now, just fault so the system doesn't hang.
*/
delay_action = 1;
break;
case 0xFF:
delay_action = 1;
break;
default:
break;
}
if (delay_action) {
/* start the queue so we can respond with error to requests */
}
}
/*
*
* Name: skd_restart_device, restart the hardware.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
/* ack all ghost interrupts */
}
/*
*
* Name: skd_stop_device, stops the device.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
int secs;
goto stop_out;
}
goto stop_out;
}
secs = 10;
cur_ticks = ddi_get_lbolt();
/* Oops - timed out */
}
}
case 0:
break;
case 1:
break;
default:
}
/* ensure all ints on device are cleared */
/* soft reset the device to unload with a clean slate */
}
/*
* CONSTRUCT
*/
static int skd_cons_skcomp(struct skd_device *);
static int skd_cons_skmsg(struct skd_device *);
static int skd_cons_skreq(struct skd_device *);
static int skd_cons_sksb(struct skd_device *);
dma_mem_t *);
/*
*
* Name: skd_construct, calls other routines to build device
* interface structures.
*
* Inputs: skdev - device state structure.
* instance - DDI instance number.
*
* Returns: Returns DDI_FAILURE on any failure otherwise returns
* DDI_SUCCESS.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static int
{
int rc = 0;
if (rc < 0) {
goto err_out;
}
if (rc < 0) {
goto err_out;
}
if (rc < 0) {
goto err_out;
}
if (rc < 0) {
goto err_out;
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
*
* Name: skd_free_phys, frees DMA memory.
*
* Inputs: skdev - device state structure.
* mem - DMA info.
*
* Returns: Nothing.
*
*/
static void
{
return;
}
}
/*
*
* Name: skd_alloc_dma_mem, allocates DMA memory.
*
* Inputs: skdev - device state structure.
* mem - DMA data structure.
* sleep - indicates whether called routine can sleep.
* atype - specified 32 or 64 bit allocation.
*
* Returns: Void pointer to mem->bp on success else NULL.
* NOTE: There are some failure modes even if sleep is set
* to KM_SLEEP, so callers MUST check the return code even
* if KM_SLEEP is passed in.
*
*/
static void *
{
};
if (atype == ATYPE_32BIT)
/*
* Allocate DMA memory.
*/
return (NULL);
}
return (NULL);
}
return (NULL);
}
if (cnt > 1) {
"cookie_count %d > 1", cnt);
return (NULL);
}
}
/*
*
* Name: skd_cons_skcomp, allocates space for the skcomp table.
*
* Inputs: skdev - device state structure.
*
* Returns: -ENOMEM if no memory otherwise NULL.
*
*/
static int
{
int rc = 0;
goto err_out;
}
return (rc);
}
/*
*
* Name: skd_cons_skmsg, allocates space for the skmsg table.
*
* Inputs: skdev - device state structure.
*
* Returns: -ENOMEM if no memory otherwise NULL.
*
*/
static int
{
int rc = 0;
uint32_t i;
(ulong_t)sizeof (struct skd_fitmsg_context),
(ulong_t)(sizeof (struct skd_fitmsg_context) *
KM_SLEEP);
for (i = 0; i < skdev->num_fitmsg_context; i++) {
i++;
break;
}
}
/* Free list is in order starting with the 0th entry. */
return (rc);
}
/*
*
* Name: skd_cons_skreq, allocates space for the skreq table.
*
* Inputs: skdev - device state structure.
*
* Returns: -ENOMEM if no memory otherwise NULL.
*
*/
static int
{
int rc = 0;
uint32_t i;
"skreq_table kmem_zalloc, struct %lu, count %u total %lu",
(ulong_t)sizeof (struct skd_request_context),
(ulong_t) (sizeof (struct skd_request_context) *
skdev->num_req_context));
KM_SLEEP);
for (i = 0; i < skdev->num_req_context; i++) {
goto err_out;
}
}
/* Free list is in order starting with the 0th entry. */
return (rc);
}
/*
*
* Name: skd_cons_sksb, allocates space for the skspcl msg buf
* and data buf.
*
* Inputs: skdev - device state structure.
*
* Returns: -ENOMEM if no memory otherwise NULL.
*
*/
static int
{
int rc = 0;
/* data_buf's DMA pointer is skspcl->db_dma_address */
goto err_out;
}
/* msg_buf DMA pointer is skspcl->mb_dma_address */
goto err_out;
}
goto err_out;
}
if (skd_format_internal_skspcl(skdev) == 0) {
goto err_out;
}
return (rc);
}
/*
*
* Name: skd_cons_sg_list, allocates the S/G list.
*
* Inputs: skdev - device state structure.
* n_sg - Number of scatter-gather entries.
* ret_dma_addr - S/G list DMA pointer.
*
* Returns: A list of FIT message descriptors.
*
*/
static struct fit_sg_descriptor
{
mem = ret_dma_addr;
/* sg_list's DMA pointer is *ret_dma_addr */
uint32_t i;
for (i = 0; i < n_sg - 1; i++) {
}
}
return (sg_list);
}
/*
* DESTRUCT (FREE)
*/
struct fit_sg_descriptor *sg_list,
/*
*
* Name: skd_destruct, call various rouines to deallocate
* space acquired during initialization.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
return;
}
}
/*
*
* Name: skd_free_skcomp, deallocates skcomp table DMA resources.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
}
/*
*
* Name: skd_free_skmsg, deallocates skmsg table DMA resources.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
uint32_t i;
return;
for (i = 0; i < skdev->num_fitmsg_context; i++) {
}
}
}
/*
*
* Name: skd_free_skreq, deallocates skspcl table DMA resources.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
uint32_t i;
return;
for (i = 0; i < skdev->num_req_context; i++) {
}
}
/*
*
* Name: skd_free_sksb, deallocates skspcl data buf and
* msg buf DMA resources.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
}
}
/*
*
* Name: skd_free_sg_list, deallocates S/G DMA resources.
*
* Inputs: skdev - device state structure.
* sg_list - S/G list itself.
* n_sg - nukmber of segments
* dma_addr - S/G list DMA address.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static void
struct fit_sg_descriptor *sg_list,
{
}
}
/*
*
* Name: skd_queue, queues the I/O request.
*
* Inputs: skdev - device state structure.
* pbuf - I/O request
*
* Returns: Nothing.
*
*/
static void
{
if (SIMPLEQ_EMPTY(waitq))
else
}
/*
*
* Name: skd_list_skreq, displays the skreq table entries.
*
* Inputs: skdev - device state structure.
* list - flag, if true displays the entry address.
*
* Returns: Returns number of skmsg entries found.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static int
{
int inx = 0;
if (list) {
while (skreq) {
if (list)
"%d: skreq=%p state=%d id=%x fid=%x "
"pbuf=%p dir=%d comp=%d\n",
inx++;
}
}
inx = 0;
if (list)
while (skreq) {
if (list)
inx++;
}
return (inx);
}
/*
*
* Name: skd_list_skmsg, displays the skmsg table entries.
*
* Inputs: skdev - device state structure.
* list - flag, if true displays the entry address.
*
* Returns: Returns number of skmsg entries found.
*
*/
static int
{
int inx = 0;
if (list) {
while (skmsgp) {
if (list)
inx++;
}
}
inx = 0;
if (list)
while (skmsgp) {
if (list)
"o=%d nxt=%p\n",
inx++;
}
return (inx);
}
/*
*
* Name: skd_get_queue_pbuf, retrieves top of queue entry and
* delinks entry from the queue.
*
* Inputs: skdev - device state structure.
* drive - device number
*
* Returns: Returns the top of the job queue entry.
*
*/
static skd_buf_private_t
{
return (pbuf);
}
/*
* PCI DRIVER GLUE
*/
/*
*
* Name: skd_pci_info, logs certain device PCI info.
*
* Inputs: skdev - device state structure.
*
* Returns: str which contains the device speed info..
*
*/
static char *
{
int pcie_reg;
str[0] = '\0';
if (pcie_reg) {
pcie_reg += 0x12;
lwidth);
}
return (str);
}
/*
* MODULE GLUE
*/
/*
*
* Name: skd_init, initializes certain values.
*
* Inputs: skdev - device state structure.
*
* Returns: Zero.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static int
{
if (skd_max_queue_depth < 1 ||
}
}
}
skd_dbg_level, 0);
skd_dbg_level = 0;
}
return (0);
}
/*
*
* Name: skd_exit, exits the driver & logs the fact.
*
* Inputs: none.
*
* Returns: Nothing.
*
*/
static void
skd_exit(void)
{
}
/*
*
* Name: skd_drive_state_to_str, converts binary drive state
* to its corresponding string value.
*
* Inputs: Drive state.
*
* Returns: String representing drive state.
*
*/
const char *
{
switch (state) {
case FIT_SR_DRIVE_OFFLINE: return ("OFFLINE");
case FIT_SR_DRIVE_INIT: return ("INIT");
case FIT_SR_DRIVE_ONLINE: return ("ONLINE");
case FIT_SR_DRIVE_BUSY: return ("BUSY");
case FIT_SR_DRIVE_FAULT: return ("FAULT");
case FIT_SR_DRIVE_DEGRADED: return ("DEGRADED");
case FIT_SR_PCIE_LINK_DOWN: return ("LINK_DOWN");
case FIT_SR_DRIVE_SOFT_RESET: return ("SOFT_RESET");
case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: return ("NEED_FW");
case FIT_SR_DRIVE_INIT_FAULT: return ("INIT_FAULT");
case FIT_SR_DRIVE_BUSY_SANITIZE:return ("BUSY_SANITIZE");
case FIT_SR_DRIVE_BUSY_ERASE: return ("BUSY_ERASE");
case FIT_SR_DRIVE_FW_BOOTING: return ("FW_BOOTING");
default: return ("???");
}
}
/*
*
* Name: skd_skdev_state_to_str, converts binary driver state
* to its corresponding string value.
*
* Inputs: Driver state.
*
* Returns: String representing driver state.
*
*/
static const char *
{
switch (state) {
case SKD_DRVR_STATE_LOAD: return ("LOAD");
case SKD_DRVR_STATE_IDLE: return ("IDLE");
case SKD_DRVR_STATE_BUSY: return ("BUSY");
case SKD_DRVR_STATE_STARTING: return ("STARTING");
case SKD_DRVR_STATE_ONLINE: return ("ONLINE");
case SKD_DRVR_STATE_PAUSING: return ("PAUSING");
case SKD_DRVR_STATE_PAUSED: return ("PAUSED");
case SKD_DRVR_STATE_DRAINING_TIMEOUT: return ("DRAINING_TIMEOUT");
case SKD_DRVR_STATE_RESTARTING: return ("RESTARTING");
case SKD_DRVR_STATE_RESUMING: return ("RESUMING");
case SKD_DRVR_STATE_STOPPING: return ("STOPPING");
case SKD_DRVR_STATE_SYNCING: return ("SYNCING");
case SKD_DRVR_STATE_FAULT: return ("FAULT");
case SKD_DRVR_STATE_DISAPPEARED: return ("DISAPPEARED");
case SKD_DRVR_STATE_BUSY_ERASE: return ("BUSY_ERASE");
case SKD_DRVR_STATE_BUSY_SANITIZE:return ("BUSY_SANITIZE");
case SKD_DRVR_STATE_BUSY_IMMINENT: return ("BUSY_IMMINENT");
case SKD_DRVR_STATE_WAIT_BOOT: return ("WAIT_BOOT");
default: return ("???");
}
}
/*
*
* Name: skd_skmsg_state_to_str, converts binary driver state
* to its corresponding string value.
*
* Inputs: Msg state.
*
* Returns: String representing msg state.
*
*/
static const char *
{
switch (state) {
case SKD_MSG_STATE_IDLE: return ("IDLE");
case SKD_MSG_STATE_BUSY: return ("BUSY");
default: return ("???");
}
}
/*
*
* Name: skd_skreq_state_to_str, converts binary req state
* to its corresponding string value.
*
* Inputs: Req state.
*
* Returns: String representing req state.
*
*/
static const char *
{
switch (state) {
case SKD_REQ_STATE_IDLE: return ("IDLE");
case SKD_REQ_STATE_SETUP: return ("SETUP");
case SKD_REQ_STATE_BUSY: return ("BUSY");
case SKD_REQ_STATE_COMPLETED: return ("COMPLETED");
case SKD_REQ_STATE_TIMEOUT: return ("TIMEOUT");
case SKD_REQ_STATE_ABORTED: return ("ABORTED");
default: return ("???");
}
}
/*
*
* Name: skd_log_skdev, logs device state & parameters.
*
* Inputs: skdev - device state structure.
* event - event (string) to log.
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_log_skmsg, logs the skmsg event.
*
* Inputs: skdev - device state structure.
* skmsg - FIT message structure.
* event - event string to log.
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_log_skreq, logs the skreq event.
*
* Inputs: skdev - device state structure.
* skreq -skreq structure.
* event - event string to log.
*
* Returns: Nothing.
*
*/
static void
{
} else {
}
}
/*
*
* Name: skd_init_mutex, initializes all mutexes.
*
* Inputs: skdev - device state structure.
*
* Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS.
*
*/
static int
{
void *intr;
/* mutexes to protect the adapter state structure. */
DDI_INTR_PRI(intr));
DDI_INTR_PRI(intr));
DDI_INTR_PRI(intr));
DDI_INTR_PRI(intr));
return (DDI_SUCCESS);
}
/*
*
* Name: skd_destroy_mutex, destroys all mutexes.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
}
}
/*
*
* Name: skd_setup_intr, setup the interrupt handling
*
* Inputs: skdev - device state structure.
* intr_type - requested DDI interrupt type.
*
* Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS.
*
*/
static int
{
uint32_t i;
/* Get number of interrupts the platform h/w supports */
DDI_SUCCESS) || count == 0) {
return (DDI_FAILURE);
}
/* Get number of available system interrupts */
DDI_SUCCESS) || avail == 0) {
return (DDI_FAILURE);
}
"req'd: %d, avail: %d",
return (DDI_FAILURE);
}
/* Allocate space for interrupt handles */
/* Allocate the interrupts */
return (DDI_FAILURE);
}
if (intr_type == DDI_INTR_TYPE_FIXED)
/* Get interrupt priority */
DDI_SUCCESS) {
return (ret);
}
/* Add the interrupt handlers */
for (i = 0; i < actual; i++) {
DDI_SUCCESS) {
return (ret);
}
}
/* Setup mutexes */
return (ret);
}
/* Get the capabilities */
/* Enable interrupts */
"ret=%xh", ret);
return (ret);
}
} else {
DDI_SUCCESS) {
"intr enable, ret=%xh", ret);
return (ret);
}
}
}
if (intr_type == DDI_INTR_TYPE_FIXED)
return (DDI_SUCCESS);
}
/*
*
* Name: skd_disable_intr, disable interrupt handling.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
rval);
}
} else {
/* Remove AIF non-block interrupts (fixed). */
DDI_SUCCESS) {
"intr#=%xh, " "rval=%xh", i, rval);
}
}
}
}
/*
*
* Name: skd_release_intr, disables interrupt handling.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
int32_t i;
int rval;
return;
}
while (i-- > 0) {
continue;
}
"htable[%d], rval=%d", i, rval);
if ((rval = ddi_intr_remove_handler(
"intr_remove_handler FAILED, "
"rval=%d", rval);
"remove_handler htable[%d]", i);
}
"FAILED, rval=%d", rval);
i);
}
}
}
/*
*
* Name: skd_dealloc_resources, deallocate resources allocated
* during attach.
*
* Inputs: dip - DDI device info pointer.
* skdev - device state structure.
* seq - bit flag representing allocated item.
* instance - device instance.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static void
{
return;
if (seq & SKD_CONSTRUCTED)
if (seq & SKD_INTR_ADDED) {
}
if (seq & SKD_DEV_IOBASE_MAPPED)
if (seq & SKD_IOMAP_IOBASE_MAPPED)
if (seq & SKD_REGS_MAPPED)
if (seq & SKD_CONFIG_SPACE_SETUP)
if (seq & SKD_SOFT_STATE_ALLOCED) {
}
}
if (skdev->s1120_devid)
}
/*
*
* Name: skd_setup_interrupt, sets up the appropriate interrupt type
* msi, msix, or fixed.
*
* Inputs: skdev - device state structure.
*
* Returns: DDI_FAILURE on failure otherwise DDI_SUCCESS.
*
*/
static int
{
int32_t i;
/*
* See what types of interrupts this adapter and platform support
*/
DDI_SUCCESS) {
return (DDI_FAILURE);
}
} else if ((itypes & DDI_INTR_TYPE_FIXED) &&
== DDI_SUCCESS) {
} else {
return (DDI_FAILURE);
}
return (rval);
}
/*
*
* Name: skd_get_properties, retrieves properties from skd.conf.
*
* Inputs: skdev - device state structure.
* dip - dev_info data structure.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static void
{
int prop_value;
"intr-type-cap", -1);
"max-scsi-reqs", -1);
"max-scsi-reqs-per-msg", -1);
"max-sgs-per-req", -1);
"dbg-level", -1);
}
/*
*
* Name: skd_wait_for_s1120, wait for device to finish
* its initialization.
*
* Inputs: skdev - device state structure.
*
* Returns: DDI_SUCCESS or DDI_FAILURE.
*
*/
static int
{
int loop_cntr = 0;
while (skdev->gendisk_on == 0) {
cur_ticks = ddi_get_lbolt();
/* Oops - timed out */
if (loop_cntr++ > 10)
break;
}
}
rc = DDI_SUCCESS;
return (rc);
}
/*
*
* Name: skd_update_props, updates certain device properties.
*
* Inputs: skdev - device state structure.
* dip - dev info structure
*
* Returns: Nothing.
*
*/
static void
{
blksize) != DDI_SUCCESS)) {
}
}
/*
*
* Name: skd_setup_devid, sets up device ID info.
*
* Inputs: skdev - device state structure.
* devid - Device ID for the DDI.
*
* Returns: DDI_SUCCESS or DDI_FAILURE.
*
*/
static int
{
if (rc != DDI_SUCCESS)
return (rc);
}
/*
*
* Name: skd_bd_attach, attach to blkdev driver
*
* Inputs: skdev - device state structure.
* dip - device info structure.
*
* Returns: DDI_SUCCESS or DDI_FAILURE.
*
*/
static int
{
int rv;
return (DDI_FAILURE);
}
if (rv != DDI_SUCCESS) {
} else {
skdev->bd_attached++;
}
return (rv);
}
/*
*
* Name: skd_bd_detach, detach from the blkdev driver.
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
if (skdev->bd_attached)
}
/*
*
* Name: skd_attach, attach sdk device driver
*
* Inputs: dip - device info structure.
* cmd - DDI attach argument (ATTACH, RESUME, etc.)
*
* Returns: DDI_SUCCESS or DDI_FAILURE.
*
*/
static int
{
int instance;
int nregs;
int inx;
int progress = 0;
(void) ddi_get_parent_data(dip);
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
/* Re-enable timer */
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/*
* Check that hardware is installed in a DMA-capable slot
*/
return (DDI_FAILURE);
}
/*
* No support for high-level interrupts
*/
if (ddi_intr_hilevel(dip, 0) != 0) {
return (DDI_FAILURE);
}
/*
* Allocate our per-device-instance structure
*/
DDI_SUCCESS) {
return (DDI_FAILURE);
}
goto skd_attach_failed;
}
break;
}
break;
}
}
goto skd_attach_failed;
}
/* Save adapter path. */
/*
* 0x0 Configuration Space
* 0x1 I/O Space
* 0x2 s1120 register space
*/
goto skd_attach_failed;
}
goto skd_attach_failed;
}
skdev->dev_memsize);
/* Get adapter PCI device information. */
goto skd_attach_failed;
}
progress |= SKD_PROBED;
/*
* Setup interrupt handler
*/
goto skd_attach_failed;
}
progress |= SKD_ATTACHED;
/*
* Give the board a chance to
* complete its initialization.
*/
(void) skd_wait_for_s1120(skdev);
goto skd_attach_failed;
}
if (*skdev->inq_serial_num)
if (*skdev->inq_product_id &&
goto skd_attach_failed;
/* Enable timer */
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/*
*
* Name: skd_halt
*
* Inputs: skdev - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
}
/*
*
* Name: skd_detach, detaches driver from the system.
*
* Inputs: dip - device info structure.
*
* Returns: DDI_SUCCESS on successful detach otherwise DDI_FAILURE.
*
*/
static int
{
int instance;
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
/* Test for packet cache inuse. */
/* Disable driver timer if no adapters. */
if (skdev->skd_timer_timeout_id != 0) {
skdev->skd_timer_timeout_id = 0;
}
if (timer_id != 0) {
}
#ifdef SKD_PM
}
#endif
/*
* Clear request queue.
*/
"detach: cancelled pbuf %p %ld <%s> %lld\n",
}
}
skd_exit();
break;
case DDI_SUSPEND:
/* Block timer. */
/* Disable driver timer if last adapter. */
if (skdev->skd_timer_timeout_id != 0) {
skdev->skd_timer_timeout_id = 0;
}
if (timer_id != 0) {
}
break;
default:
rv1 = DDI_FAILURE;
break;
}
if (rv1 != DDI_SUCCESS) {
} else {
}
if (rv1 != DDI_SUCCESS)
return (DDI_FAILURE);
return (rv1);
}
/*
*
* Name: skd_devid_init, calls skd_setup_devid to setup
* the device's devid structure.
*
* Inputs: arg - device state structure.
* dip - dev_info structure.
* devid - devid structure.
*
* Returns: Nothing.
*
*/
/* ARGSUSED */ /* Upstream common source with other platforms. */
static int
{
return (0);
}
/*
*
* Name: skd_bd_driveinfo, retrieves device's info.
*
* Inputs: drive - drive data structure.
* arg - device state structure.
*
* Returns: Nothing.
*
*/
static void
{
if (skdev->inquiry_is_valid != 0) {
}
}
/*
*
* Name: skd_bd_mediainfo, retrieves device media info.
*
* Inputs: arg - device state structure.
* media - container for media info.
*
* Returns: Zero.
*
*/
static int
{
return (0);
}
/*
*
* Name: skd_rw, performs R/W requests for blkdev driver.
*
* Inputs: skdev - device state structure.
* xfer - tranfer structure.
* dir - I/O direction.
*
* Returns: EAGAIN if device is not online. EIO if blkdev wants us to
* be a dump device (for now).
* Value returned by skd_start().
*
*/
static int
{
/*
* The x_flags structure element is not defined in Oracle Solaris
*/
/* We'll need to fix this in order to support dump on this device. */
return (EIO);
return (EAGAIN);
}
return (ENOMEM);
skdev->ios_queued++;
return (0);
}
/*
*
* Name: skd_bd_read, performs blkdev read requests.
*
* Inputs: arg - device state structure.
* xfer - tranfer request structure.
*
* Returns: Value return by skd_rw().
*
*/
static int
{
}
/*
*
* Name: skd_bd_write, performs blkdev write requests.
*
* Inputs: arg - device state structure.
* xfer - tranfer request structure.
*
* Returns: Value return by skd_rw().
*
*/
static int
{
}