summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/intel/io/aac/aac.c1295
-rw-r--r--usr/src/uts/intel/io/aac/aac.h42
-rw-r--r--usr/src/uts/intel/io/aac/aac_ioctl.c316
-rw-r--r--usr/src/uts/intel/io/aac/aac_regs.h57
4 files changed, 939 insertions, 771 deletions
diff --git a/usr/src/uts/intel/io/aac/aac.c b/usr/src/uts/intel/io/aac/aac.c
index 8219d00bd8..ec37f51b92 100644
--- a/usr/src/uts/intel/io/aac/aac.c
+++ b/usr/src/uts/intel/io/aac/aac.c
@@ -86,6 +86,10 @@ _NOTE(CONSTCOND) } while (0)
#define AAC_SENSE_DATA_DESCR_LEN \
(sizeof (struct scsi_descr_sense_hdr) + \
sizeof (struct scsi_information_sense_descr))
+#define AAC_ARQ64_LENGTH \
+ (sizeof (struct scsi_arq_status) + \
+ AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
+
/* NOTE: GETG4ADDRTL(cdbp) is int32_t */
#define AAC_GETGXADDR(cmdlen, cdbp) \
((cmdlen == 6) ? GETG0ADDR(cdbp) : \
@@ -149,12 +153,21 @@ _NOTE(CONSTCOND) } while (0)
((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
(arg0), (arg1), (arg2), (arg3)))
+/* Operations to init FIB */
+#define AAC_SET_FIBSIZE 0
+#define AAC_SET_SGTABLE 1
+#define AAC_SET_BLKNO 2
+#define AAC_SET_DISKNO 3
+
#define AAC_IOCMD_SYNC (1 << 0)
#define AAC_IOCMD_ASYNC (1 << 1)
#define AAC_IOCMD_OUTSTANDING (1 << 2)
#define AAC_IOCMD_ALL (AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC | \
AAC_IOCMD_OUTSTANDING)
+/* Poll time for aac_do_poll_io() */
+#define AAC_POLL_TIME 60000 /* 60 seconds */
+
/*
* Hardware access functions
*/
@@ -175,16 +188,15 @@ static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
/*
- * Interrupt handler funtions
+ * Interrupt handler functions
*/
static uint_t aac_intr_old(caddr_t);
static uint_t aac_intr_new(caddr_t);
static uint_t aac_softintr(caddr_t);
/*
- * Internal function in attach
+ * Internal functions in attach
*/
-static void aac_intr_norm(struct aac_softstate *, struct aac_cmd *);
static int aac_check_card_type(struct aac_softstate *);
static int aac_check_firmware(struct aac_softstate *);
static int aac_common_attach(struct aac_softstate *);
@@ -207,7 +219,7 @@ static struct aac_fib *aac_grab_sync_fib(struct aac_softstate *,
static void aac_release_sync_fib(struct aac_softstate *);
/*
- * Waiting/complete queue operation funcitons
+ * Waiting/complete queue operation functions
*/
static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
@@ -215,31 +227,35 @@ static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
/*
* FIB queue operation functions
*/
-static int aac_fib_enqueue(struct aac_softstate *, int, struct aac_fib *);
-static int aac_resp_enqueue(struct aac_softstate *, int, struct aac_fib *);
-static int aac_fib_dequeue(struct aac_softstate *, int, struct aac_fib **,
- struct aac_cmd **);
+static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
+static int aac_fib_dequeue(struct aac_softstate *, int, int *);
/*
* Slot operation functions
*/
static int aac_create_slots(struct aac_softstate *);
static void aac_destroy_slots(struct aac_softstate *);
+static void aac_destroy_fibs(struct aac_softstate *);
static struct aac_slot *aac_get_slot(struct aac_softstate *);
static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
static void aac_free_fib(struct aac_slot *);
/*
- * Internal funcitons
+ * Internal functions
*/
-static size_t aac_cmd_fib(struct aac_softstate *, struct aac_cmd *);
+static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *);
+static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *, int);
+static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *, int);
+static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *, int);
+static void aac_cmd_fib_scsi(struct aac_softstate *, struct aac_cmd *, int);
static void aac_start_waiting_io(struct aac_softstate *);
static void aac_drain_comp_q(struct aac_softstate *);
+int aac_do_io(struct aac_softstate *, struct aac_cmd *);
static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
-int aac_do_async_io(struct aac_softstate *, struct aac_cmd *);
+static int aac_do_async_io(struct aac_softstate *, struct aac_cmd *);
static int aac_send_command(struct aac_softstate *, struct aac_slot *);
-static void aac_dma_sync(ddi_dma_handle_t, off_t, size_t, uint_t);
+static void aac_dma_sync_ac(struct aac_cmd *);
static int aac_shutdown(struct aac_softstate *);
static int aac_reset_adapter(struct aac_softstate *);
@@ -313,7 +329,7 @@ static struct cb_ops aac_cb_ops = {
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
- nodev, /* cb_prop_op */
+ ddi_prop_op, /* cb_prop_op */
NULL, /* streamtab */
D_64BIT | D_NEW | D_MP | D_HOTPLUG, /* cb_flag */
CB_REV, /* cb_rev */
@@ -1029,6 +1045,43 @@ aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
return (AACOK);
}
+static void
+aac_handle_io(struct aac_softstate *softs, int index)
+{
+ struct aac_slot *slotp;
+ struct aac_cmd *acp;
+ uint32_t fast;
+
+ fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
+ index >>= 2;
+
+ /* Make sure firmware reported index is valid */
+ ASSERT(index >= 0 && index < softs->total_slots);
+ slotp = &softs->io_slot[index];
+ ASSERT(slotp->index == index);
+ acp = slotp->acp;
+ ASSERT(acp != NULL && acp->slotp == slotp);
+
+ (void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
+
+ /*
+ * For fast response IO, the firmware do not return any FIB data,
+ * so we need to fill in the FIB status and state so that FIB users
+ * can handle it correctly.
+ */
+ if (fast) {
+ uint32_t state;
+
+ state = slotp->fibp->Header.XferState;
+ /* Update state for CPU not for device, no DMA sync needed */
+ slotp->fibp->Header.XferState = state | AAC_FIBSTATE_DONEADAP;
+ *((uint32_t *)(slotp->fibp->data)) = ST_OK;
+ }
+
+ /* Handle completed ac */
+ acp->ac_comp(softs, acp);
+}
+
/*
* Interrupt handler for New Comm. interface
* New Comm. interface use a different mechanism for interrupt. No explict
@@ -1039,7 +1092,6 @@ static uint_t
aac_intr_new(caddr_t arg)
{
struct aac_softstate *softs = (struct aac_softstate *)arg;
- struct aac_fib *fibp;
uint32_t index;
/* AACDB_PRINT(softs, CE_NOTE, "INTR! new"); */
@@ -1050,26 +1102,9 @@ aac_intr_new(caddr_t arg)
return (DDI_INTR_UNCLAIMED);
do {
if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
- struct aac_cmd *acp;
- uint32_t fast;
-
- fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
- index >>= 2;
-
- /* Make sure firmware reported index is valid */
- ASSERT(index >= 0 && index < softs->total_slots);
- ASSERT(softs->io_slot[index].index != -1);
-
- acp = softs->io_slot[index].acp;
- ASSERT(acp != NULL);
- if (fast) {
- fibp = softs->io_slot[index].fibp;
- fibp->Header.XferState |=
- AAC_FIBSTATE_DONEADAP;
- *((uint32_t *)(fibp->data)) = 0;
- }
- aac_intr_norm(softs, acp);
+ aac_handle_io(softs, index);
} else if (index != 0xfffffffeul) {
+ struct aac_fib *fibp; /* FIB in AIF queue */
int i;
/* AIF received */
@@ -1107,23 +1142,26 @@ static uint_t
aac_intr_old(caddr_t arg)
{
struct aac_softstate *softs = (struct aac_softstate *)arg;
- struct aac_cmd *acp;
- struct aac_fib *fibp;
uint16_t status;
int rval;
/* AACDB_PRINT(softs, CE_NOTE, "INTR! old"); */
status = AAC_STATUS_GET(softs);
if (status & AAC_DB_RESPONSE_READY) {
+ int slot_idx;
+
/* ACK the intr */
AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
(void) AAC_STATUS_GET(softs);
do {
- rval = aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
- &fibp, &acp);
- if (rval == 0 && acp)
- aac_intr_norm(softs, acp);
- } while (rval == 0);
+ if (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
+ &slot_idx) == AACOK) {
+ aac_handle_io(softs, slot_idx);
+ } else {
+ break;
+ }
+ /*CONSTCOND*/
+ } while (1);
aac_start_waiting_io(softs);
ddi_trigger_softintr(softs->softint_id);
@@ -1132,7 +1170,7 @@ aac_intr_old(caddr_t arg)
/* ACK the intr */
AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
(void) AAC_STATUS_GET(softs);
- aac_dma_sync(softs->comm_space_dma_handle,
+ (void) ddi_dma_sync(softs->comm_space_dma_handle,
AACOFFSET(struct aac_comm_space, adapter_print_buf),
AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
cmn_err(CE_NOTE, "MSG From Adapter: %s",
@@ -1140,14 +1178,37 @@ aac_intr_old(caddr_t arg)
AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
return (DDI_INTR_CLAIMED);
} else if (status & AAC_DB_COMMAND_READY) {
+ int aif_idx;
+
AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
(void) AAC_STATUS_GET(softs);
- rval = aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q,
- &fibp, &acp);
- if (rval == 0 && fibp) {
+ rval = aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx);
+ if (rval == AACOK) {
+ struct aac_fib *fibp;
+ uint32_t addr, size;
+
+ ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
+ fibp = &softs->comm_space->adapter_fibs[aif_idx];
(void) aac_handle_aif(softs, fibp);
- if (aac_resp_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
- fibp) == AACERR)
+
+ /* Complete AIF back to adapter with good status */
+ if (fibp->Header.XferState & AAC_FIBSTATE_FROMADAP) {
+ fibp->Header.XferState |= AAC_FIBSTATE_DONEHOST;
+ ((int *)fibp->data)[0] = ST_OK;
+ if (fibp->Header.Size > sizeof (struct aac_fib))
+ fibp->Header.Size =
+ sizeof (struct aac_fib);
+ }
+
+ /* Put the AIF response on the response queue */
+ addr = softs->comm_space->adapter_fibs[aif_idx]. \
+ Header.SenderFibAddress;
+ size = softs->comm_space->adapter_fibs[aif_idx]. \
+ Header.Size;
+ softs->comm_space->adapter_fibs[aif_idx]. \
+ Header.ReceiverFibAddress = addr;
+ if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
+ addr, size) == AACERR)
cmn_err(CE_NOTE, "!AIF ack failed");
}
return (DDI_INTR_CLAIMED);
@@ -1170,35 +1231,46 @@ aac_intr_old(caddr_t arg)
}
/*
+ * Set pkt_reason and OR in pkt_statistics flag
+ */
+static void
+aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
+ uchar_t reason, uint_t stat)
+{
+ _NOTE(ARGUNUSED(softs))
+
+ AACDB_PRINT(softs, CE_NOTE, "acp=0x%p, reason=%x, stat=%x",
+ (void *)acp, reason, stat);
+ if (acp->pkt->pkt_reason == CMD_CMPLT)
+ acp->pkt->pkt_reason = reason;
+ acp->pkt->pkt_statistics |= stat;
+}
+
+/*
* Handle a finished pkt of AAC_CMD_HARD_INTR mode
*/
static void
-aac_hard_callback(struct aac_softstate *softs, struct aac_cmd *acp,
- uchar_t reason)
+aac_hard_callback(struct aac_softstate *softs, struct aac_cmd *acp)
{
- acp->pkt->pkt_reason = reason;
aac_cmd_enqueue(&softs->q_comp, acp);
}
/*
- * Handle a finished pkt of non AAC_CMD_HARD_INTR mode
+ * Handle a finished pkt of soft SCMD
*/
static void
-aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp,
- uchar_t reason)
+aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
{
- struct scsi_pkt *pkt = acp->pkt;
+ ASSERT(acp->pkt);
- /* AAC_CMD_NO_INTR means no complete callback */
- ASSERT(!(acp->flags & AAC_CMD_NO_INTR) || (reason == CMD_CMPLT));
+ acp->flags |= AAC_CMD_CMPLT;
- pkt->pkt_reason = reason;
- if (reason == CMD_CMPLT)
- pkt->pkt_state |=
- STATE_GOT_BUS |
- STATE_GOT_TARGET |
- STATE_SENT_CMD;
+ acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
+ STATE_SENT_CMD;
+ if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
+ acp->pkt->pkt_resid = 0;
+ /* AAC_CMD_NO_INTR means no complete callback */
if (!(acp->flags & AAC_CMD_NO_INTR)) {
aac_cmd_enqueue(&softs->q_comp, acp);
ddi_trigger_softintr(softs->softint_id);
@@ -1208,62 +1280,69 @@ aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp,
/*
* Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
*/
+
+/*
+ * Handle completed logical device IO command
+ */
static void
-aac_intr_norm(struct aac_softstate *softs, struct aac_cmd *acp)
+aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
{
- struct aac_slot *slotp;
- uint8_t status;
+ struct aac_slot *slotp = acp->slotp;
+ struct aac_blockread_response *resp;
- ASSERT(acp != NULL);
- ASSERT(acp->slotp != NULL);
- ASSERT(acp->flags & AAC_CMD_HARD_INTR);
+ /*
+ * block_read/write has a similar response header, use blockread
+ * response for both.
+ */
+ resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
+ if (resp->Status == ST_OK) {
+ acp->pkt->pkt_resid = 0;
+ acp->pkt->pkt_state |= STATE_XFERRED_DATA;
+ } else {
+ aac_set_arq_data_hwerr(acp);
+ }
- slotp = acp->slotp;
- aac_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
+ ASSERT(!(acp->flags & AAC_CMD_SYNC));
+ aac_release_slot(softs, slotp);
+ acp->slotp = NULL;
+ acp->flags |= AAC_CMD_CMPLT;
- if (slotp->fibp->Header.XferState & AAC_FIBSTATE_ASYNC) {
- status = slotp->fibp->data[0];
- aac_release_slot(softs, slotp);
- acp->slotp = NULL;
- if (status == 0)
- acp->pkt->pkt_state |= STATE_XFERRED_DATA;
- else
- aac_set_arq_data_hwerr(acp);
- acp->state = AAC_CMD_CMPLT;
+ if (!(acp->flags & AAC_CMD_NO_INTR))
+ aac_hard_callback(softs, acp);
+ else { /* Poll IO */
+ mutex_enter(&softs->event_mutex);
+ cv_broadcast(&softs->event);
+ mutex_exit(&softs->event_mutex);
+ }
+}
- aac_hard_callback(softs, acp, CMD_CMPLT);
- } else if (slotp->fibp->Header.XferState & AAC_FIBSTATE_REXPECTED) {
- /*
- * NOTE: use ASYNC to differentiate fibcmd & sendfib,
- * see ioctl_send_fib().
- */
- struct aac_fib *fibp;
+/*
+ * Handle completed IOCTL command
+ */
+void
+aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
+{
+ struct aac_slot *slotp = acp->slotp;
- fibp = &acp->fib;
- ASSERT(fibp->Header.Size <= softs->aac_max_fib_size);
+ /* Get the size of the response FIB from its FIB.Header.Size field */
+ acp->fib_size = slotp->fibp->Header.Size;
- bcopy(slotp->fibp, fibp, fibp->Header.Size);
- aac_release_slot(softs, acp->slotp);
- acp->slotp = NULL;
- acp->state = AAC_CMD_CMPLT;
+ ASSERT(acp->fib_size <= softs->aac_max_fib_size);
+ bcopy(slotp->fibp, acp->fibp, acp->fib_size);
- mutex_enter(&softs->event_mutex);
- /*
- * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
- * may wait on softs->event, so use cv_broadcast() instead
- * of cv_signal().
- */
- cv_broadcast(&softs->event);
- mutex_exit(&softs->event_mutex);
- } else {
- /* Hardware error */
- aac_release_slot(softs, acp->slotp);
- acp->slotp = NULL;
- aac_set_arq_data_hwerr(acp);
- acp->state = AAC_CMD_CMPLT;
+ ASSERT(acp->flags & AAC_CMD_SYNC);
+ aac_release_slot(softs, slotp);
+ acp->slotp = NULL;
+ acp->flags |= AAC_CMD_CMPLT;
- aac_hard_callback(softs, acp, CMD_CMPLT);
- }
+ /*
+ * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
+ * may wait on softs->event, so use cv_broadcast() instead
+ * of cv_signal().
+ */
+ mutex_enter(&softs->event_mutex);
+ cv_broadcast(&softs->event);
+ mutex_exit(&softs->event_mutex);
}
/*
@@ -1538,6 +1617,20 @@ aac_check_firmware(struct aac_softstate *softs)
softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
+ /* Setup FIB operations for logical devices */
+ if (softs->flags & AAC_FLAGS_RAW_IO)
+ softs->aac_cmd_fib = aac_cmd_fib_rawio;
+ else if (softs->flags & AAC_FLAGS_SG_64BIT)
+ softs->aac_cmd_fib = aac_cmd_fib_brw64;
+ else
+ softs->aac_cmd_fib = aac_cmd_fib_brw;
+
+ /* 64-bit LBA needs descriptor format sense data */
+ softs->slen = sizeof (struct scsi_arq_status);
+ if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
+ softs->slen < AAC_ARQ64_LENGTH)
+ softs->slen = AAC_ARQ64_LENGTH;
+
cmn_err(CE_NOTE,
"!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
softs->aac_max_fibs, softs->aac_max_fib_size,
@@ -1705,6 +1798,16 @@ aac_common_attach(struct aac_softstate *softs)
DBCALLED(softs, 1);
/*
+ * Do a little check here to make sure there aren't any outstanding
+ * FIBs in the message queue. At this point there should not be and
+ * if there are they are probably left over from another instance of
+ * the driver like when the system crashes and the crash dump driver
+ * gets loaded.
+ */
+ while (AAC_OUTB_GET(softs) != 0xfffffffful)
+ ;
+
+ /*
* Wait the card to complete booting up before do anything that
* attempts to communicate with it.
*/
@@ -1831,6 +1934,8 @@ aac_common_attach(struct aac_softstate *softs)
error:
if (softs->state == AAC_STATE_RESET)
return (AACERR);
+ if (softs->total_fibs > 0)
+ aac_destroy_fibs(softs);
if (softs->total_slots > 0)
aac_destroy_slots(softs);
if (softs->comm_space_dma_handle)
@@ -1844,28 +1949,11 @@ error:
static void
aac_common_detach(struct aac_softstate *softs)
{
- int i;
-
DBCALLED(softs, 1);
(void) aac_shutdown(softs);
- /* Release FIBs */
- for (i = 0; i < softs->total_slots; i++) {
- struct aac_slot *slotp;
-
- slotp = &(softs->io_slot[i]);
- if (slotp->fib_phyaddr == 0)
- continue;
- aac_free_fib(slotp);
- slotp->index = -1;
- softs->total_fibs--;
- }
- ASSERT(softs->total_fibs == 0);
- softs->free_io_slot_head = -1;
- softs->free_io_slot_tail = -1;
- softs->free_io_slot_len = 0;
-
+ aac_destroy_fibs(softs);
aac_destroy_slots(softs);
aac_free_comm_space(softs);
}
@@ -1949,7 +2037,7 @@ aac_sync_fib(struct aac_softstate *softs, uint32_t cmd,
fibp->Header.ReceiverFibAddress = softs->sync_mode.fib_phyaddr;
fibp->Header.SenderData = 0;
- aac_dma_sync(softs->comm_space_dma_handle,
+ (void) ddi_dma_sync(softs->comm_space_dma_handle,
AACOFFSET(struct aac_comm_space, sync_fib), AAC_FIB_SIZE,
DDI_DMA_SYNC_FORDEV);
@@ -2038,66 +2126,17 @@ aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
* separate queue/notify interface).
*/
static int
-aac_fib_enqueue(struct aac_softstate *softs, int queue, struct aac_fib *fibp)
+aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
+ uint32_t fib_size)
{
uint32_t pi, ci;
- uint32_t fib_size;
- uint32_t fib_addr;
DBCALLED(softs, 2);
- mutex_enter(&softs->fib_mutex);
- fib_size = fibp->Header.Size;
- fib_addr = fibp->Header.ReceiverFibAddress;
-
- /* Get the producer/consumer indices */
- pi = softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX];
- ci = softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX];
-
- /*
- * Wrap the queue first before we check the queue to see
- * if it is full
- */
- if (pi >= aac_qinfo[queue].size)
- pi = 0;
-
- /* XXX queue full */
- if ((pi + 1) == ci) {
- mutex_exit(&softs->fib_mutex);
- return (AACERR);
- }
+ ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
- /* Fill in queue entry */
- (softs->qentries[queue] + pi)->aq_fib_size = fib_size;
- (softs->qentries[queue] + pi)->aq_fib_addr = fib_addr;
-
- /* Update producer index */
- softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
-
- mutex_exit(&softs->fib_mutex);
-
- if (aac_qinfo[queue].notify != 0)
- AAC_NOTIFY(softs, aac_qinfo[queue].notify);
-
- return (AACOK);
-}
-
-/*
- * Put our response to an AIF on the response queue
- */
-static int
-aac_resp_enqueue(struct aac_softstate *softs, int queue, struct aac_fib *fibp)
-{
- uint32_t pi, ci;
- uint32_t fib_size;
- uint32_t fib_addr;
-
- DBCALLED(softs, 2);
-
- /* Tell the adapter where the FIB is */
- fib_size = fibp->Header.Size;
- fib_addr = fibp->Header.SenderFibAddress;
- fibp->Header.ReceiverFibAddress = fib_addr;
+ if (queue == AAC_ADAP_NORM_CMD_Q)
+ mutex_enter(&softs->fib_mutex);
/* Get the producer/consumer indices */
pi = softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX];
@@ -2112,6 +2151,8 @@ aac_resp_enqueue(struct aac_softstate *softs, int queue, struct aac_fib *fibp)
/* XXX queue full */
if ((pi + 1) == ci) {
+ if (queue == AAC_ADAP_NORM_CMD_Q)
+ mutex_exit(&softs->fib_mutex);
return (AACERR);
}
@@ -2122,6 +2163,9 @@ aac_resp_enqueue(struct aac_softstate *softs, int queue, struct aac_fib *fibp)
/* Update producer index */
softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1;
+ if (queue == AAC_ADAP_NORM_CMD_Q)
+ mutex_exit(&softs->fib_mutex);
+
if (aac_qinfo[queue].notify != 0)
AAC_NOTIFY(softs, aac_qinfo[queue].notify);
return (AACOK);
@@ -2132,14 +2176,16 @@ aac_resp_enqueue(struct aac_softstate *softs, int queue, struct aac_fib *fibp)
* success or AACERR if the queue is empty.
*/
static int
-aac_fib_dequeue(struct aac_softstate *softs, int queue, struct aac_fib **fibpp,
- struct aac_cmd **acpp)
+aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
{
- uint32_t pi, ci, index, fast;
- int error = 0, unfull = 0;
+ uint32_t pi, ci;
+ int unfull = 0;
+ int error = AACOK;
DBCALLED(softs, 2);
+ ASSERT(idxp);
+
mutex_enter(&softs->fib_mutex);
/* Get the producer/consumer indices */
@@ -2167,30 +2213,17 @@ aac_fib_dequeue(struct aac_softstate *softs, int queue, struct aac_fib **fibpp,
/* Fetch the entry */
switch (queue) {
+ case AAC_HOST_NORM_RESP_Q:
+ case AAC_HOST_HIGH_RESP_Q:
+ *idxp = (softs->qentries[queue] + ci)->aq_fib_addr;
+ break;
+
case AAC_HOST_NORM_CMD_Q:
case AAC_HOST_HIGH_CMD_Q:
- index = (softs->qentries[queue] + ci)->aq_fib_addr /
+ *idxp = (softs->qentries[queue] + ci)->aq_fib_addr /
sizeof (struct aac_fib);
- ASSERT((index >= 0) && (index < AAC_ADAPTER_FIBS));
- *fibpp = &softs->comm_space->adapter_fibs[index];
- ASSERT(*fibpp != NULL);
- *acpp = NULL;
break;
- case AAC_HOST_NORM_RESP_Q:
- case AAC_HOST_HIGH_RESP_Q:
- index = (softs->qentries[queue] + ci)->aq_fib_addr;
- fast = (index & 1);
- index >>= 2;
- ASSERT((index >= 0) && (index < softs->total_fibs));
- *acpp = softs->io_slot[index].acp;
- ASSERT(*acpp != NULL);
- *fibpp = softs->io_slot[index].fibp;
- if (fast) {
- (*fibpp)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
- *((uint32_t *)((*fibpp)->data)) = 0;
- }
- break;
default:
cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
error = AACERR;
@@ -2955,7 +2988,7 @@ aac_abort_iocmds(struct aac_softstate *softs, int iocmd)
aac_release_slot(softs, slotp);
acp->slotp = NULL;
- acp->state = AAC_CMD_ABORT;
+ acp->flags |= AAC_CMD_ABORT;
if ((slotp->fibp->Header.XferState &
AAC_FIBSTATE_ASYNC) == 0) {
@@ -2969,7 +3002,8 @@ aac_abort_iocmds(struct aac_softstate *softs, int iocmd)
* condition when reseted.
*/
aac_set_arq_data_reset(softs, acp);
- aac_hard_callback(softs, acp, reason);
+ acp->pkt->pkt_reason = reason;
+ aac_hard_callback(softs, acp);
}
}
}
@@ -2978,7 +3012,7 @@ aac_abort_iocmds(struct aac_softstate *softs, int iocmd)
if (iocmd & AAC_IOCMD_SYNC) {
while ((acp = aac_cmd_dequeue(&softs->q_wait_sync)) != NULL) {
/* IOCTL */
- acp->state = AAC_CMD_ABORT;
+ acp->flags |= AAC_CMD_ABORT;
mutex_enter(&softs->event_mutex);
cv_broadcast(&softs->event);
@@ -2990,9 +3024,10 @@ aac_abort_iocmds(struct aac_softstate *softs, int iocmd)
if (iocmd & AAC_IOCMD_ASYNC) {
while ((acp = aac_cmd_dequeue(&softs->q_wait)) != NULL) {
aac_set_arq_data_reset(softs, acp);
- acp->state = AAC_CMD_ABORT;
+ acp->flags |= AAC_CMD_ABORT;
- aac_hard_callback(softs, acp, reason);
+ acp->pkt->pkt_reason = reason;
+ aac_hard_callback(softs, acp);
}
}
@@ -3022,8 +3057,6 @@ aac_reset_adapter(struct aac_softstate *softs)
/* Disable interrupt */
AAC_DISABLE_INTR(softs);
- aac_abort_iocmds(softs, AAC_IOCMD_ALL);
-
health = aac_check_adapter_health(softs);
if (health == -1)
goto finish;
@@ -3069,6 +3102,7 @@ aac_reset_adapter(struct aac_softstate *softs)
rval = AACOK;
finish:
+ aac_abort_iocmds(softs, AAC_IOCMD_ALL);
AAC_ENABLE_INTR(softs);
return (rval);
}
@@ -3163,7 +3197,7 @@ aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
return (1);
}
-static void
+void
aac_free_dmamap(struct aac_cmd *acp)
{
/* Free dma mapping */
@@ -3175,6 +3209,10 @@ aac_free_dmamap(struct aac_cmd *acp)
if (acp->abp != NULL) { /* free non-aligned buf DMA */
ASSERT(acp->buf_dma_handle);
+ if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
+ ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
+ (uint8_t *)acp->abp, acp->bp->b_bcount,
+ DDI_DEV_AUTOINCR);
ddi_dma_mem_free(&acp->abh);
acp->abp = NULL;
}
@@ -3190,15 +3228,11 @@ aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
{
struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
struct aac_cmd *acp;
- struct aac_fib *fibp;
union scsi_cdb *cdbp;
struct buf *bp;
uchar_t cmd;
int target = ap->a_target;
int lun = ap->a_lun;
- int capacity;
- uint64_t blkno;
- uint32_t blkcnt;
int rval;
DBCALLED(softs, 2);
@@ -3215,30 +3249,46 @@ aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
rw_enter(&softs->errlock, RW_READER);
- /* Init ac and pkt */
acp = PKT2AC(pkt);
cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
- bp = acp->bp;
cmd = cdbp->scc_cmd;
- acp->flags |= (pkt->pkt_flags & FLAG_NOINTR) ? AAC_CMD_NO_INTR : 0;
- acp->state = AAC_CMD_INCMPLT;
+ bp = acp->bp;
+
+ /*
+ * Reinitialize some fields of ac and pkt; the packet may
+ * have been resubmitted
+ */
+ acp->flags &= ~(AAC_CMD_NO_INTR | AAC_CMD_CMPLT | \
+ AAC_CMD_ABORT | AAC_CMD_TIMEOUT);
+ acp->timeout = acp->pkt->pkt_time;
+ if (pkt->pkt_flags & FLAG_NOINTR)
+ acp->flags |= AAC_CMD_NO_INTR;
+ pkt->pkt_reason = CMD_CMPLT;
pkt->pkt_state = 0;
- pkt->pkt_statistics = STAT_SYNC;
+ pkt->pkt_statistics = 0;
*pkt->pkt_scbp = 0; /* clear arq scsi_status */
+ if (acp->flags & AAC_CMD_DMA_VALID) {
+ pkt->pkt_resid = acp->bcount;
+ /* Consistent packets need to be sync'ed first */
+ if ((acp->flags & AAC_CMD_CONSISTENT) &&
+ (acp->flags & AAC_CMD_BUF_WRITE))
+ aac_dma_sync_ac(acp);
+ } else {
+ pkt->pkt_resid = 0;
+ }
+
AACDB_PRINT_SCMD(softs, acp);
switch (cmd) {
case SCMD_INQUIRY: /* inquiry */
- acp->flags |= AAC_CMD_SOFT_INTR;
aac_free_dmamap(acp);
aac_inquiry(softs, pkt, cdbp, bp);
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
case SCMD_READ_CAPACITY: /* read capacity */
- acp->flags |= AAC_CMD_SOFT_INTR;
if (bp && bp->b_un.b_addr && bp->b_bcount) {
struct scsi_capacity cap;
uint64_t last_lba;
@@ -3258,7 +3308,7 @@ aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
bcopy(&cap, bp->b_un.b_addr, 8);
pkt->pkt_state |= STATE_XFERRED_DATA;
}
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
@@ -3267,7 +3317,6 @@ aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
if (cdbp->cdb_opaque[1] != SSVC_ACTION_READ_CAPACITY_G4)
goto unknown;
- acp->flags |= AAC_CMD_SOFT_INTR;
if (bp && bp->b_un.b_addr && bp->b_bcount) {
struct scsi_capacity_16 cap16;
int cap_len = sizeof (struct scsi_capacity_16);
@@ -3283,126 +3332,87 @@ aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
bcopy(&cap16, bp->b_un.b_addr, cap_len);
pkt->pkt_state |= STATE_XFERRED_DATA;
}
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
case SCMD_READ_G4: /* read_16 */
case SCMD_WRITE_G4: /* write_16 */
- if ((softs->flags & AAC_FLAGS_RAW_IO) == 0) {
- AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
- goto unknown;
+ if (softs->flags & AAC_FLAGS_RAW_IO) {
+ /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
+ acp->blkno = ((uint64_t) \
+ GETG4ADDR(cdbp) << 32) | \
+ (uint32_t)GETG4ADDRTL(cdbp);
+ goto do_io;
}
- /*FALLTHRU*/
+ AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
+ goto unknown;
case SCMD_READ: /* read_6 */
- case SCMD_READ_G1: /* read_10 */
case SCMD_WRITE: /* write_6 */
- case SCMD_WRITE_G1: /* write_10 */
- acp->flags |= AAC_CMD_HARD_INTR;
- if (!(acp->flags & AAC_CMD_DMA_VALID) ||
- !(acp->fib.Header.XferState & AAC_FIBSTATE_HOSTOWNED)) {
- rval = TRAN_BADPKT;
- break;
- }
-
- blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
- fibp = &acp->fib;
- if (softs->flags & AAC_FLAGS_RAW_IO) {
- /* Fill in correct blkno */
- struct aac_raw_io *io =
- (struct aac_raw_io *)&fibp->data[0];
-
- io->BlockNumber = blkno;
- io->Flags = (acp->flags & AAC_CMD_BUF_READ) ? 1:0;
- blkcnt = io->ByteCount / AAC_BLK_SIZE;
- } else if (softs->flags & AAC_FLAGS_SG_64BIT) {
- /* Fill in correct blkno */
- if (acp->flags & AAC_CMD_BUF_READ) {
- struct aac_blockread64 *br =
- (struct aac_blockread64 *)&fibp->data[0];
+ acp->blkno = GETG0ADDR(cdbp);
+ goto do_io;
- br->BlockNumber = (uint32_t)blkno;
- blkcnt = br->SectorCount;
- } else {
- struct aac_blockwrite64 *bw =
- (struct aac_blockwrite64 *)&fibp->data[0];
-
- bw->BlockNumber = (uint32_t)blkno;
- blkcnt = bw->SectorCount;
- }
- } else {
- /* Fill in correct blkno */
- if (acp->flags & AAC_CMD_BUF_READ) {
- struct aac_blockread *br =
- (struct aac_blockread *)&fibp->data[0];
+ case SCMD_READ_G1: /* read_10 */
+ case SCMD_WRITE_G1: /* write_10 */
+ acp->blkno = (uint32_t)GETG1ADDR(cdbp);
+do_io:
+ if (acp->flags & AAC_CMD_DMA_VALID) {
+ uint64_t cnt_size = acp->dvp->size;
- br->BlockNumber = (uint32_t)blkno;
- blkcnt = br->ByteCount / AAC_BLK_SIZE;
+ /*
+ * If LBA > array size AND rawio, the
+ * adapter may hang. So check it before
+ * sending.
+ * NOTE: (blkno + blkcnt) may overflow
+ */
+ if ((acp->blkno < cnt_size) &&
+ ((acp->blkno + acp->bcount /
+ AAC_BLK_SIZE) <= cnt_size)) {
+ softs->aac_cmd_fib(softs, acp,
+ AAC_SET_BLKNO);
+ rval = aac_do_io(softs, acp);
} else {
- struct aac_blockwrite *bw =
- (struct aac_blockwrite *)&fibp->data[0];
-
- bw->BlockNumber = (uint32_t)blkno;
- blkcnt = bw->ByteCount / AAC_BLK_SIZE;
- }
- }
-
- /*
- * If lba > array size AND rawio, the adapter may hang. So
- * check it before sending.
- * NOTE: (blkno + blkcnt) may overflow
- */
- if ((blkno >= softs->container[target].size) ||
- ((blkno + blkcnt) > softs->container[target].size)) {
/*
- * Request exceed the capacity of disk set error
- * block number to last LBA + 1
+ * Request exceeds the capacity of disk,
+ * set error block number to last LBA
+ * + 1.
*/
- aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
- 0x21, 0x00, softs->container[target].size);
- aac_soft_callback(softs, acp, CMD_CMPLT);
- rval = TRAN_ACCEPT;
- break;
- }
-
- if ((acp->flags & AAC_CMD_NO_INTR) ||
- (acp->flags & AAC_CMD_SOFT_INTR)) {
- /* Poll pkt */
- if (aac_do_poll_io(softs, acp) == AACOK) {
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_set_arq_data(pkt,
+ KEY_ILLEGAL_REQUEST, 0x21,
+ 0x00, cnt_size);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
- } else {
- rval = TRAN_BADPKT;
}
+ } else if (acp->bcount == 0) {
+ /* For 0 length IO, just return ok */
+ aac_soft_callback(softs, acp);
+ rval = TRAN_ACCEPT;
} else {
- /* Async pkt */
- if (aac_do_async_io(softs, acp) == AACOK)
- rval = TRAN_ACCEPT;
- else
- rval = TRAN_BUSY;
+ rval = TRAN_BADPKT;
}
break;
case SCMD_MODE_SENSE: /* mode_sense_6 */
- case SCMD_MODE_SENSE_G1: /* mode_sense_10 */
- acp->flags |= AAC_CMD_SOFT_INTR;
+ case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
+ int capacity;
+
aac_free_dmamap(acp);
if (softs->container[target].size > 0xffffffffull)
capacity = 0xfffffffful; /* 64-bit LBA */
else
capacity = softs->container[target].size;
aac_mode_sense(softs, pkt, cdbp, bp, capacity);
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
+ }
case SCMD_TEST_UNIT_READY:
case SCMD_REQUEST_SENSE:
case SCMD_FORMAT:
case SCMD_START_STOP:
case SCMD_SYNCHRONIZE_CACHE:
- acp->flags |= AAC_CMD_SOFT_INTR;
aac_free_dmamap(acp);
if (bp && bp->b_un.b_addr && bp->b_bcount) {
if (acp->flags & AAC_CMD_BUF_READ) {
@@ -3412,18 +3422,17 @@ aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
}
pkt->pkt_state |= STATE_XFERRED_DATA;
}
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
case SCMD_DOORLOCK:
- acp->flags |= AAC_CMD_SOFT_INTR;
aac_free_dmamap(acp);
if (pkt->pkt_cdbp[4] & 0x01)
softs->container[target].locked = 1;
else
softs->container[target].locked = 0;
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
@@ -3432,7 +3441,7 @@ unknown:
AACDB_PRINT(softs, CE_CONT, "SCMD not supported");
aac_free_dmamap(acp);
aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
- aac_soft_callback(softs, acp, CMD_CMPLT);
+ aac_soft_callback(softs, acp);
rval = TRAN_ACCEPT;
break;
}
@@ -3553,6 +3562,11 @@ aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
DBCALLED(NULL, 2);
+ if (acp->fibp) {
+ kmem_free(acp->fibp, acp->fib_kmsz);
+ acp->fibp = NULL;
+ acp->fib_kmsz = 0;
+ }
aac_free_dmamap(acp);
ASSERT(acp->slotp == NULL);
scsi_hba_pkt_free(ap, pkt);
@@ -3567,31 +3581,28 @@ aac_tran_init_pkt(struct scsi_address *ap,
struct aac_cmd *acp, *new_acp;
uint_t dma_flags = 0;
int (*cb)(caddr_t);
- size_t transfer_num;
+ int kf;
+ aac_cmd_fib_t aac_cmd_fib;
int rval;
DBCALLED(softs, 2);
- cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
+ if (callback == SLEEP_FUNC) {
+ cb = DDI_DMA_SLEEP;
+ kf = KM_SLEEP;
+ } else {
+ cb = DDI_DMA_DONTWAIT;
+ kf = KM_NOSLEEP;
+ }
/* Allocate pkt */
if (pkt == NULL) {
- int slen, hbalen;
+ int slen;
/* Force auto request sense */
- /* 64-bit LBA needs descriptor format sense data */
- slen = (sizeof (struct scsi_extended_sense) <
- AAC_SENSE_DATA_DESCR_LEN) ?
- (sizeof (struct scsi_arq_status) +
- AAC_SENSE_DATA_DESCR_LEN -
- sizeof (struct scsi_extended_sense)) :
- sizeof (struct scsi_arq_status);
- if (statuslen > slen)
- slen = statuslen;
- hbalen = sizeof (struct aac_cmd) - sizeof (struct aac_fib) +
- softs->aac_max_fib_size;
+ slen = (statuslen > softs->slen) ? statuslen : softs->slen;
pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
- slen, tgtlen, hbalen, callback, arg);
+ slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
if (pkt == NULL) {
AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
return (NULL);
@@ -3599,7 +3610,6 @@ aac_tran_init_pkt(struct scsi_address *ap,
acp = new_acp = PKT2AC(pkt);
acp->pkt = pkt;
acp->cmdlen = cmdlen;
- acp->slotp = NULL;
/*
* We will still use this point to fake some
@@ -3612,6 +3622,9 @@ aac_tran_init_pkt(struct scsi_address *ap,
acp->flags |= AAC_CMD_CONSISTENT;
if (flags & PKT_DMA_PARTIAL)
acp->flags |= AAC_CMD_DMA_PARTIAL;
+
+ acp->dvp = &softs->container[ap->a_target];
+ acp->ac_comp = aac_ld_complete;
} else {
acp = PKT2AC(pkt);
new_acp = NULL;
@@ -3642,21 +3655,19 @@ aac_tran_init_pkt(struct scsi_address *ap,
rval = DDI_SUCCESS;
if (!acp->buf_dma_handle)
rval = ddi_dma_alloc_handle(softs->devinfo_p,
- &softs->buf_dma_attr, cb, NULL,
+ &softs->buf_dma_attr, cb, arg,
&acp->buf_dma_handle);
if (rval != DDI_SUCCESS) {
AACDB_PRINT(softs, CE_WARN,
"Can't allocate DMA handle, errno=%d", rval);
- if (new_acp)
- scsi_hba_pkt_free(ap, pkt);
- return (NULL);
+ goto error_out;
}
/* Bind buf */
if ((((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) &&
((bp->b_bcount & AAC_DMA_ALIGN_MASK) == 0)) {
rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
- bp, dma_flags, DDI_DMA_SLEEP, NULL,
+ bp, dma_flags, cb, arg,
&acp->cookie, &acp->left_cookien);
} else {
size_t bufsz;
@@ -3670,7 +3681,7 @@ aac_tran_init_pkt(struct scsi_address *ap,
rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
&aac_acc_attr, DDI_DMA_STREAMING,
- DDI_DMA_SLEEP, NULL, &acp->abp, &bufsz, &acp->abh);
+ cb, arg, &acp->abp, &bufsz, &acp->abh);
if (rval != DDI_SUCCESS) {
AACDB_PRINT(softs, CE_NOTE,
@@ -3683,8 +3694,8 @@ aac_tran_init_pkt(struct scsi_address *ap,
bcopy(bp->b_un.b_addr, acp->abp, bp->b_bcount);
rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
- NULL, acp->abp, bufsz, dma_flags, DDI_DMA_SLEEP,
- 0, &acp->cookie, &acp->left_cookien);
+ NULL, acp->abp, bufsz, dma_flags, cb, arg,
+ &acp->cookie, &acp->left_cookien);
}
switch (rval) {
@@ -3730,11 +3741,69 @@ aac_tran_init_pkt(struct scsi_address *ap,
}
}
- /* Build FIB for this ac/pkt and return remaining byte count */
- transfer_num = aac_cmd_fib(softs, acp);
- if (transfer_num == 0)
+ /* Move window to build s/g map */
+ if (acp->left_cookien == 0) {
+ if ((acp->cur_win + 1) < acp->total_nwin) {
+ off_t off;
+ size_t len;
+
+ acp->cur_win++;
+ rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
+ &off, &len, &acp->cookie, &acp->left_cookien);
+ if (rval != DDI_SUCCESS) {
+ AACDB_PRINT(softs, CE_WARN,
+ "ddi_dma_getwin() fail %d", rval);
+ return (NULL);
+ }
+ } else {
+ AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
+ return (NULL);
+ }
+ }
+
+ ASSERT(acp->left_cookien > 0);
+ if (acp->left_cookien > softs->aac_sg_tablesize) {
+ AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d\n",
+ acp->left_cookien);
+ bioerror(bp, EINVAL);
goto error_out;
- pkt->pkt_resid = bp->b_bcount - transfer_num;
+ }
+
+ aac_cmd_fib = softs->aac_cmd_fib;
+
+ aac_cmd_fib(softs, acp, AAC_SET_FIBSIZE);
+ if (acp->fibp && acp->fib_kmsz < acp->fib_size) {
+ kmem_free(acp->fibp, acp->fib_kmsz);
+ acp->fibp = NULL;
+ acp->fib_kmsz = 0;
+ }
+ if (acp->fibp == NULL) {
+ acp->fibp = kmem_alloc(acp->fib_size, kf);
+ if (acp->fibp == NULL) {
+ AACDB_PRINT(softs, CE_WARN,
+ "fail to kmem_alloc memory for ac fib");
+ bioerror(bp, ENOMEM);
+ goto error_out;
+ }
+ acp->fib_kmsz = acp->fib_size;
+ }
+ aac_cmd_fib(softs, acp, AAC_SET_SGTABLE);
+ /*
+ * Note: The old DMA engine do not correctly handle
+ * dma_attr_maxxfer attribute. So we have to ensure
+ * it by ourself.
+ */
+ if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
+ AACDB_PRINT(softs, CE_NOTE, "large xfer size received %d\n",
+ acp->bcount);
+ bioerror(bp, EINVAL);
+ goto error_out;
+ }
+
+ acp->total_xfer += acp->bcount;
+
+ /* Return remaining byte count */
+ pkt->pkt_resid = bp->b_bcount - acp->total_xfer;
AACDB_PRINT_TRAN(softs, "bp=0x%p, xfered=%d/%d, resid=%d",
(void *)bp->b_un.b_addr, (int)acp->total_xfer,
@@ -3748,10 +3817,8 @@ aac_tran_init_pkt(struct scsi_address *ap,
return (pkt);
error_out:
- AACDB_PRINT(softs, CE_WARN, "Cannot bind buf for DMA");
- aac_free_dmamap(acp);
if (new_acp)
- scsi_hba_pkt_free(ap, pkt);
+ aac_tran_destroy_pkt(ap, pkt);
return (NULL);
}
@@ -3763,19 +3830,10 @@ static void
aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
{
struct aac_cmd *acp = PKT2AC(pkt);
- struct buf *bp;
DBCALLED(NULL, 2);
- if (acp->buf_dma_handle) {
- aac_dma_sync(acp->buf_dma_handle, 0, 0,
- (acp->flags & AAC_CMD_BUF_WRITE) ?
- DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
- if (acp->abp != NULL) {
- bp = acp->bp;
- bcopy(acp->abp, bp->b_un.b_addr, bp->b_bcount);
- }
- }
+ aac_dma_sync_ac(acp);
}
/*
@@ -3864,7 +3922,7 @@ aac_hba_setup(struct aac_softstate *softs)
hba_tran->tran_quiesce = aac_tran_quiesce;
hba_tran->tran_unquiesce = aac_tran_unquiesce;
rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
- hba_tran, SCSI_HBA_TRAN_CLONE);
+ hba_tran, 0);
if (rval != DDI_SUCCESS) {
scsi_hba_tran_free(hba_tran);
AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
@@ -3874,35 +3932,19 @@ aac_hba_setup(struct aac_softstate *softs)
return (AACOK);
}
-static size_t
-aac_cmd_fib(struct aac_softstate *softs, struct aac_cmd *acp)
+/*
+ * FIB setup operations
+ */
+
+/*
+ * Init FIB header
+ */
+static void
+aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp)
{
- int count, sgelem;
- off_t off;
- size_t len;
- struct aac_sg_table *sgmap;
- struct aac_sg_table64 *sgmap64;
- struct aac_sg_tableraw *sgmapraw;
- ddi_dma_handle_t dma_handle;
- ddi_dma_cookie_t *cookiep;
- uint_t cookien;
- uint32_t *bytecountp, *sgcountp, cur_total_xfer, next_total_xfer;
- struct scsi_pkt *pkt;
- struct scsi_address *ap;
- struct aac_fib *fibp;
- uint16_t *seccountp, *fib_datasizep;
-
- fibp = &acp->fib;
- pkt = acp->pkt;
- ap = &pkt->pkt_address;
- dma_handle = acp->buf_dma_handle;
- cookiep = &acp->cookie;
- cookien = acp->left_cookien;
-
- if (cookien == 0 && acp->total_nwin == 1)
- return (0); /* nothing to be transfered */
- /* Fill in fib header */
- fibp->Header.XferState =
+ struct aac_fib *fibp = acp->fibp;
+
+ fibp->Header.XferState = (uint32_t)(
AAC_FIBSTATE_HOSTOWNED |
AAC_FIBSTATE_INITIALISED |
AAC_FIBSTATE_EMPTY |
@@ -3910,160 +3952,187 @@ aac_cmd_fib(struct aac_softstate *softs, struct aac_cmd *acp)
AAC_FIBSTATE_REXPECTED |
AAC_FIBSTATE_NORM |
AAC_FIBSTATE_ASYNC |
- AAC_FIBSTATE_FAST_RESPONSE; /* enable fast io */
- fibp->Header.Command = ContainerCommand;
+ AAC_FIBSTATE_FAST_RESPONSE /* enable fast io */);
fibp->Header.StructType = AAC_FIBTYPE_TFIB;
fibp->Header.Flags = 0; /* don't care */
- fibp->Header.Size = sizeof (struct aac_fib_header);
fibp->Header.SenderSize = softs->aac_max_fib_size;
- fibp->Header.ReceiverFibAddress = 0;
fibp->Header.SenderData = 0; /* don't care */
- fib_datasizep = &fibp->Header.Size; /* will be filled in later */
-
- if (softs->flags & AAC_FLAGS_RAW_IO) {
- /* Fill in fib data */
- struct aac_raw_io *io;
+}
+/*
+ * Init FIB for raw IO command
+ */
+static void
+aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp, int op)
+{
+ struct aac_fib *fibp = acp->fibp;
+ struct aac_raw_io *io = (struct aac_raw_io *)&fibp->data[0];
+
+ if (op == AAC_SET_FIBSIZE) {
+ acp->fib_size = sizeof (struct aac_fib_header) + \
+ sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
+ sizeof (struct aac_sg_entryraw);
+ } else if (op == AAC_SET_BLKNO) {
+ io->BlockNumber = acp->blkno;
+ io->ContainerId = acp->dvp->cid;
+ } else if (op == AAC_SET_SGTABLE) {
+ struct aac_sg_entryraw *sgentp = io->SgMapRaw.SgEntryRaw;
+
+ aac_cmd_fib_header(softs, acp);
+ fibp->Header.Size = acp->fib_size;
fibp->Header.Command = RawIo;
- io = (struct aac_raw_io *)&fibp->data[0];
- *fib_datasizep += sizeof (struct aac_raw_io);
- io->ContainerId = AAC_TRAN2SOFTS(ap->a_hba_tran)-> \
- container[ap->a_target].cid;
+
+ io->Flags = (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0;
io->BpTotal = 0;
io->BpComplete = 0;
- sgmapraw = &io->SgMapRaw;
- bytecountp = &io->ByteCount;
- sgcountp = &sgmapraw->SgCount;
- sgelem = sizeof (struct aac_sg_entryraw);
- } else if (softs->flags & AAC_FLAGS_SG_64BIT) {
+
+ /* Fill SG table */
+ io->SgMapRaw.SgCount = acp->left_cookien;
+
+ acp->bcount = 0;
+ do {
+ sgentp->SgAddress = acp->cookie.dmac_laddress;
+ sgentp->SgByteCount = acp->cookie.dmac_size;
+ sgentp->Next = 0;
+ sgentp->Prev = 0;
+ sgentp->Flags = 0;
+ sgentp++;
+
+ acp->bcount += acp->cookie.dmac_size;
+ acp->left_cookien--;
+ if (acp->left_cookien > 0)
+ ddi_dma_nextcookie(acp->buf_dma_handle,
+ &acp->cookie);
+ else
+ break;
+ /*CONSTCOND*/
+ } while (1);
+
+ io->ByteCount = acp->bcount;
+ }
+}
+
+/* Init FIB for 64-bit block IO command */
+static void
+aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp, int op)
+{
+ struct aac_fib *fibp = acp->fibp;
+ struct aac_blockread64 *br = (struct aac_blockread64 *)&fibp->data[0];
+
+ if (op == AAC_SET_FIBSIZE) {
+ acp->fib_size = sizeof (struct aac_fib_header) + \
+ sizeof (struct aac_blockread64) + \
+ (acp->left_cookien - 1) * \
+ sizeof (struct aac_sg_entry64);
+ } else if (op == AAC_SET_BLKNO) {
+ br->BlockNumber = (uint32_t)acp->blkno;
+ br->ContainerId = acp->dvp->cid;
+ } else if (op == AAC_SET_SGTABLE) {
+ struct aac_sg_entry64 *sgentp = br->SgMap64.SgEntry64;
+
+ aac_cmd_fib_header(softs, acp);
+ fibp->Header.Size = acp->fib_size;
fibp->Header.Command = ContainerCommand64;
- /* Fill in fib data */
+
+ /*
+ * The definitions for aac_blockread64 and aac_blockwrite64
+ * are the same.
+ */
+ br->Command = (acp->flags & AAC_CMD_BUF_READ) ?
+ VM_CtHostRead64 : VM_CtHostWrite64;
+ br->Pad = 0;
+ br->Flags = 0;
+
+ /* Fill SG table */
+ br->SgMap64.SgCount = acp->left_cookien;
+
+ acp->bcount = 0;
+ do {
+ sgentp->SgAddress = acp->cookie.dmac_laddress;
+ sgentp->SgByteCount = acp->cookie.dmac_size;
+ sgentp++;
+
+ acp->bcount += acp->cookie.dmac_size;
+ acp->left_cookien--;
+ if (acp->left_cookien > 0)
+ ddi_dma_nextcookie(acp->buf_dma_handle,
+ &acp->cookie);
+ else
+ break;
+ /*CONSTCOND*/
+ } while (1);
+
+ br->SectorCount = acp->bcount / AAC_BLK_SIZE;
+ }
+}
+
+/* Init FIB for block IO command */
+static void
+aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp, int op)
+{
+ struct aac_fib *fibp = acp->fibp;
+ struct aac_blockread *br = (struct aac_blockread *)&fibp->data[0];
+
+ if (op == AAC_SET_FIBSIZE) {
if (acp->flags & AAC_CMD_BUF_READ) {
- struct aac_blockread64 *br;
-
- br = (struct aac_blockread64 *)&fibp->data[0];
- *fib_datasizep += sizeof (struct aac_blockread64);
- br->Command = VM_CtHostRead64;
- br->ContainerId = AAC_TRAN2SOFTS(ap->a_hba_tran)-> \
- container[ap->a_target].cid;
- br->Pad = 0;
- br->Flags = 0;
- sgmap64 = &br->SgMap64;
- seccountp = &br->SectorCount;
+ acp->fib_size = sizeof (struct aac_fib_header) + \
+ sizeof (struct aac_blockread) + \
+ (acp->left_cookien - 1) * \
+ sizeof (struct aac_sg_entry);
} else {
- struct aac_blockwrite64 *bw;
-
- bw = (struct aac_blockwrite64 *)&fibp->data[0];
- *fib_datasizep += sizeof (struct aac_blockwrite64);
- bw->Command = VM_CtHostWrite64;
- bw->ContainerId = AAC_TRAN2SOFTS(ap->a_hba_tran)-> \
- container[ap->a_target].cid;
- bw->Pad = 0;
- bw->Flags = 0;
- sgmap64 = &bw->SgMap64;
- seccountp = &bw->SectorCount;
+ acp->fib_size = sizeof (struct aac_fib_header) + \
+ sizeof (struct aac_blockwrite) + \
+ (acp->left_cookien - 1) * \
+ sizeof (struct aac_sg_entry);
}
- sgcountp = &sgmap64->SgCount;
- sgelem = sizeof (struct aac_sg_entry64);
- } else {
+ } else if (op == AAC_SET_BLKNO) {
+ /*
+ * aac_blockread and aac_blockwrite have the similar
+ * structure head, so use br for bw here
+ */
+ br->BlockNumber = (uint32_t)acp->blkno;
+ br->ContainerId = acp->dvp->cid;
+ } else if (op == AAC_SET_SGTABLE) {
+ struct aac_sg_table *sgmap;
+ struct aac_sg_entry *sgentp;
+
+ aac_cmd_fib_header(softs, acp);
+ fibp->Header.Size = acp->fib_size;
fibp->Header.Command = ContainerCommand;
- /* Fill in fib data */
- if (acp->flags & AAC_CMD_BUF_READ) {
- struct aac_blockread *br;
- br = (struct aac_blockread *)&fibp->data[0];
- *fib_datasizep += sizeof (struct aac_blockread);
+ if (acp->flags & AAC_CMD_BUF_READ) {
br->Command = VM_CtBlockRead;
- br->ContainerId = AAC_TRAN2SOFTS(ap->a_hba_tran)-> \
- container[ap->a_target].cid;
sgmap = &br->SgMap;
- bytecountp = &br->ByteCount;
} else {
- struct aac_blockwrite *bw;
+ struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
- bw = (struct aac_blockwrite *)&fibp->data[0];
- *fib_datasizep += sizeof (struct aac_blockwrite);
bw->Command = VM_CtBlockWrite;
- bw->ContainerId = AAC_TRAN2SOFTS(ap->a_hba_tran)-> \
- container[ap->a_target].cid;
bw->Stable = CUNSTABLE;
sgmap = &bw->SgMap;
- bytecountp = &bw->ByteCount;
}
- sgcountp = &sgmap->SgCount;
- sgelem = sizeof (struct aac_sg_entry);
- }
- /* Move cookie and window to build s/g map */
- if (cookien == 0) { /* we need to move window */
- if ((acp->cur_win + 1) < acp->total_nwin) {
- int rval;
+ /* Fill SG table */
+ sgmap->SgCount = acp->left_cookien;
+ sgentp = sgmap->SgEntry;
- acp->cur_win++;
- rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
- &off, &len, cookiep, &cookien);
- if (rval != DDI_SUCCESS)
- return (0);
- } else {
- return (0);
- }
- }
-
- count = 0;
- cur_total_xfer = 0;
- next_total_xfer = cookiep->dmac_size;
- /*
- * Cookie loop
- * Note: The old DMA engine do not correctly handle dma_attr_maxxfer
- * attribute. So we have to ensure it by ourself.
- */
- while (count < softs->aac_sg_tablesize &&
- next_total_xfer <= softs->buf_dma_attr.dma_attr_maxxfer) {
- if (softs->flags & AAC_FLAGS_RAW_IO) {
- sgmapraw->SgEntryRaw[count].SgAddress =
- cookiep->dmac_laddress;
- sgmapraw->SgEntryRaw[count].SgByteCount =
- cookiep->dmac_size;
- sgmapraw->SgEntryRaw[count].Next = 0;
- sgmapraw->SgEntryRaw[count].Prev = 0;
- sgmapraw->SgEntryRaw[count].Flags = 0;
- } else if (softs->flags & AAC_FLAGS_SG_64BIT) {
- sgmap64->SgEntry64[count].SgAddress =
- cookiep->dmac_laddress;
- sgmap64->SgEntry64[count].SgByteCount =
- cookiep->dmac_size;
- } else {
- sgmap->SgEntry[count].SgAddress =
- cookiep->dmac_laddress;
- sgmap->SgEntry[count].SgByteCount =
- cookiep->dmac_size;
- }
+ acp->bcount = 0;
+ do {
+ sgentp->SgAddress = acp->cookie.dmac_laddress;
+ sgentp->SgByteCount = acp->cookie.dmac_size;
+ sgentp++;
+
+ acp->bcount += acp->cookie.dmac_size;
+ acp->left_cookien--;
+ if (acp->left_cookien > 0)
+ ddi_dma_nextcookie(acp->buf_dma_handle,
+ &acp->cookie);
+ else
+ break;
+ /*CONSTCOND*/
+ } while (1);
- count++;
- cur_total_xfer = next_total_xfer;
- cookien--;
- if (cookien > 0)
- ddi_dma_nextcookie(dma_handle, cookiep);
- else
- break;
- next_total_xfer += cookiep->dmac_size;
+ br->ByteCount = acp->bcount;
}
-
- if ((softs->flags & AAC_FLAGS_SG_64BIT) &&
- (softs->flags & AAC_FLAGS_RAW_IO) == 0)
- *seccountp = (uint16_t)(cur_total_xfer/AAC_BLK_SIZE);
- else
- *bytecountp = cur_total_xfer;
- *sgcountp = count;
-
- acp->left_cookien = cookien;
- acp->total_xfer += cur_total_xfer;
- AACDB_PRINT_TRAN(softs, " blks xfered=%d", cur_total_xfer >> 9);
-
- /* Calculate fib data size */
- *fib_datasizep += (count - 1) * sgelem;
-
- return (acp->total_xfer);
}
static void
@@ -4074,19 +4143,14 @@ aac_start_io(struct aac_softstate *softs, struct aac_slot *slotp,
/* Set ac and pkt */
acp->slotp = slotp;
- acp->fib.Header.ReceiverFibAddress = slotp->fib_phyaddr;
- acp->fib.Header.SenderFibAddress = slotp->index << 2;
- bcopy(&acp->fib, slotp->fibp,
- acp->fib.Header.Size); /* only copy data of needed length */
- aac_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
+ acp->fibp->Header.ReceiverFibAddress = slotp->fib_phyaddr;
+ acp->fibp->Header.SenderFibAddress = slotp->index << 2;
+ bcopy(acp->fibp, slotp->fibp,
+ acp->fibp->Header.Size); /* only copy data of needed length */
+ (void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
if (acp->pkt) { /* ac from ioctl has no pkt */
acp->pkt->pkt_state =
- STATE_GOT_BUS |
- STATE_GOT_TARGET |
- STATE_SENT_CMD;
- acp->timeout = acp->pkt->pkt_time;
- } else {
- acp->timeout = AAC_IOCTL_TIMEOUT;
+ STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
}
acp->start_time = ddi_get_time();
@@ -4101,12 +4165,16 @@ aac_start_io(struct aac_softstate *softs, struct aac_slot *slotp,
if (softs->flags & AAC_FLAGS_NEW_COMM) {
rval = aac_send_command(softs, slotp);
} else {
+ uint32_t addr, size;
+
/*
* If fib can not be enqueued, the adapter is in an abnormal
* state, there will be no interrupt to us.
*/
+ addr = slotp->fibp->Header.ReceiverFibAddress;
+ size = slotp->fibp->Header.Size;
rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
- slotp->fibp);
+ addr, size);
}
/*
@@ -4117,9 +4185,18 @@ aac_start_io(struct aac_softstate *softs, struct aac_slot *slotp,
AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
aac_release_slot(softs, acp->slotp);
acp->slotp = NULL;
- acp->pkt->pkt_state &= ~STATE_SENT_CMD;
- aac_hard_callback(softs, acp, CMD_INCOMPLETE);
- ddi_trigger_softintr(softs->softint_id);
+ if (acp->pkt) {
+ acp->pkt->pkt_state &= ~STATE_SENT_CMD;
+ aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
+ }
+ if (!(acp->flags & AAC_CMD_NO_INTR)) {
+ aac_hard_callback(softs, acp);
+ ddi_trigger_softintr(softs->softint_id);
+ } else { /* Poll IO */
+ mutex_enter(&softs->event_mutex);
+ cv_broadcast(&softs->event);
+ mutex_exit(&softs->event_mutex);
+ }
}
}
@@ -4177,6 +4254,14 @@ aac_drain_comp_q(struct aac_softstate *softs)
break;
}
+ if (acp->pkt->pkt_reason == CMD_CMPLT) {
+ /*
+ * Consistent packets need to be sync'ed first
+ */
+ if ((acp->flags & AAC_CMD_CONSISTENT) &&
+ (acp->flags & AAC_CMD_BUF_READ))
+ aac_dma_sync_ac(acp);
+ }
if (acp->pkt->pkt_comp)
(*acp->pkt->pkt_comp)(acp->pkt);
}
@@ -4254,6 +4339,27 @@ aac_free_fib(struct aac_slot *slotp)
slotp->fib_phyaddr = 0;
}
+static void
+aac_destroy_fibs(struct aac_softstate *softs)
+{
+ int i;
+
+ for (i = 0; i < softs->total_slots; i++) {
+ struct aac_slot *slotp;
+
+ slotp = &(softs->io_slot[i]);
+ if (slotp->fib_phyaddr == 0)
+ continue;
+ aac_free_fib(slotp);
+ slotp->index = -1;
+ softs->total_fibs--;
+ }
+ ASSERT(softs->total_fibs == 0);
+ softs->free_io_slot_head = -1;
+ softs->free_io_slot_tail = -1;
+ softs->free_io_slot_len = 0;
+}
+
static int
aac_create_slots(struct aac_softstate *softs)
{
@@ -4334,60 +4440,58 @@ aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
mutex_exit(&softs->slot_mutex);
}
+int
+aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
+{
+ if (aac_do_async_io(softs, acp) == AACOK) {
+ /*
+ * Because sync FIB is always 512 bytes and used for critical
+ * functions, async FIB is used for poll IO.
+ */
+ if (acp->flags & AAC_CMD_NO_INTR) {
+ /* Poll pkt */
+ if (aac_do_poll_io(softs, acp) != AACOK)
+ return (TRAN_BADPKT);
+ }
+ return (TRAN_ACCEPT);
+ }
+ return (TRAN_BUSY);
+}
+
static int
aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
{
- struct aac_fib *ac_fibp, *sync_fibp;
- int rval;
-
- ASSERT(acp);
- ASSERT(softs);
-
- ac_fibp = &acp->fib;
+ ASSERT(softs && acp);
/*
- * When new comm. enabled, large FIBs are used for IO requests.
- * Since sync FIB is always 512 bytes, async FIB is used with
- * new comm. for poll IO.
+ * Interrupt is disabled in panic mode, we have to poll
+ * the adapter by ourselves.
*/
- if (softs->flags & AAC_FLAGS_NEW_COMM) {
- rval = AACOK;
- ac_fibp->Header.XferState &= ~AAC_FIBSTATE_ASYNC;
-
- if (aac_do_async_io(softs, acp) != AACOK) {
- AACDB_PRINT(softs, CE_CONT, "Poll IO failed");
- return (AACERR);
- }
-
- /*
- * Interrupt is disabled in panic mode, we have to poll
- * the adapter by ourselves.
- */
- if (ddi_in_panic()) {
- while (acp->state == AAC_CMD_INCMPLT)
- (void) aac_intr_new((caddr_t)softs);
- if (acp->state == AAC_CMD_ABORT)
- rval = AACERR;
- } else {
- ac_fibp->Header.XferState &= ~AAC_FIBSTATE_ASYNC;
- mutex_enter(&softs->event_mutex);
- while (acp->state == AAC_CMD_INCMPLT)
- cv_wait(&softs->event, &softs->event_mutex);
- if (acp->state == AAC_CMD_ABORT)
- rval = AACERR;
- mutex_exit(&softs->event_mutex);
+ if (ddi_in_panic()) {
+ uint_t (*intr_handler)(caddr_t);
+ int i;
+
+ intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
+ aac_intr_new : aac_intr_old;
+ for (i = 0; i < AAC_POLL_TIME; i++) {
+ (void) intr_handler((caddr_t)softs);
+ if (acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))
+ break;
+ drv_usecwait(1000);
}
+ if (!(acp->flags & AAC_CMD_CMPLT) && acp->pkt)
+ aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
+ (STAT_TIMEOUT | STAT_ABORTED));
} else {
- sync_fibp = aac_grab_sync_fib(softs, SLEEP_FUNC);
- /* Only copy data of needed length */
- bcopy(ac_fibp, sync_fibp, ac_fibp->Header.Size);
-
- rval = aac_sync_fib(softs, ContainerCommand, sync_fibp,
- ac_fibp->Header.Size);
- aac_release_sync_fib(softs);
+ mutex_enter(&softs->event_mutex);
+ while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
+ cv_wait(&softs->event, &softs->event_mutex);
+ mutex_exit(&softs->event_mutex);
}
- return (rval);
+ if (acp->flags & AAC_CMD_CMPLT)
+ return (AACOK);
+ return (AACERR);
}
/*
@@ -4395,12 +4499,12 @@ aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
* they are executed in order. Out-of-order execution of io requests
* is not allowed.
*/
-int
+static int
aac_do_async_io(struct aac_softstate *softs, struct aac_cmd *acp)
{
int rval = AACOK;
- if (acp->fib.Header.XferState & AAC_FIBSTATE_ASYNC)
+ if (acp->fibp->Header.XferState & AAC_FIBSTATE_ASYNC)
/* Async FIB io request enters q_wait */
aac_cmd_enqueue(&softs->q_wait, acp);
else
@@ -4413,10 +4517,27 @@ aac_do_async_io(struct aac_softstate *softs, struct aac_cmd *acp)
}
static void
-aac_dma_sync(ddi_dma_handle_t handle, off_t offset, size_t length, uint_t type)
+aac_dma_sync_ac(struct aac_cmd *acp)
{
- if (ddi_dma_sync(handle, offset, length, type) == DDI_FAILURE)
- cmn_err(CE_WARN, "!DMA sync failed");
+ if (acp->buf_dma_handle) {
+ if (acp->flags & AAC_CMD_BUF_WRITE) {
+ if (acp->abp != NULL)
+ ddi_rep_put8(acp->abh,
+ (uint8_t *)acp->bp->b_un.b_addr,
+ (uint8_t *)acp->abp, acp->bp->b_bcount,
+ DDI_DEV_AUTOINCR);
+ (void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
+ DDI_DMA_SYNC_FORDEV);
+ } else {
+ (void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
+ DDI_DMA_SYNC_FORCPU);
+ if (acp->abp != NULL)
+ ddi_rep_get8(acp->abh,
+ (uint8_t *)acp->bp->b_un.b_addr,
+ (uint8_t *)acp->abp, acp->bp->b_bcount,
+ DDI_DEV_AUTOINCR);
+ }
+ }
}
/*
@@ -4433,29 +4554,26 @@ static int
aac_handle_aif(struct aac_softstate *softs, struct aac_fib *fibp)
{
struct aac_aif_command *aif;
- int cid;
int devcfg_needed;
- struct aac_fib_context *ctx;
int current, next;
- ASSERT(softs != NULL);
- ASSERT(fibp != NULL);
-
if (fibp->Header.Command != AifRequest) {
cmn_err(CE_NOTE, "!Unknown command from controller: 0x%x",
fibp->Header.Command);
return (AACERR);
}
+ /* Update internal container state */
aif = (struct aac_aif_command *)&fibp->data[0];
AACDB_PRINT_AIF(softs, aif);
- cid = aif->data.EN.data.ECC.container[0];
devcfg_needed = 0;
switch (aif->command) {
- case AifCmdDriverNotify:
+ case AifCmdDriverNotify: {
+ int cid = aif->data.EN.data.ECC.container[0];
+
switch (aif->data.EN.type) {
case AifDenMorphComplete:
case AifDenVolumeExtendComplete:
@@ -4466,6 +4584,7 @@ aac_handle_aif(struct aac_softstate *softs, struct aac_fib *fibp)
if (softs->devcfg_wait_on == aif->data.EN.type)
devcfg_needed = 1;
break;
+ }
case AifCmdEventNotify:
switch (aif->data.EN.type) {
@@ -4515,6 +4634,8 @@ aac_handle_aif(struct aac_softstate *softs, struct aac_fib *fibp)
/* Modify AIF contexts */
if (softs->aifq_filled) {
+ struct aac_fib_context *ctx;
+
for (ctx = softs->fibctx; ctx; ctx = ctx->next) {
if (next == ctx->ctx_idx)
ctx->ctx_wrap = 1;
@@ -4527,14 +4648,6 @@ aac_handle_aif(struct aac_softstate *softs, struct aac_fib *fibp)
/* Wakeup applications */
cv_broadcast(&softs->aifv);
mutex_exit(&softs->aifq_mutex);
-
- /* Complete AIF back to adapter with good status */
- if (fibp->Header.XferState & AAC_FIBSTATE_FROMADAP) {
- fibp->Header.XferState |= AAC_FIBSTATE_DONEHOST;
- ((int *)fibp->data)[0] = 0; /* ST_OK */
- if (fibp->Header.Size > sizeof (struct aac_fib))
- fibp->Header.Size = sizeof (struct aac_fib);
- }
return (AACOK);
}
diff --git a/usr/src/uts/intel/io/aac/aac.h b/usr/src/uts/intel/io/aac/aac.h
index 84de962018..a1d0b8d654 100644
--- a/usr/src/uts/intel/io/aac/aac.h
+++ b/usr/src/uts/intel/io/aac/aac.h
@@ -57,7 +57,7 @@ extern "C" {
#define AAC_DRIVER_MAJOR_VERSION 2
#define AAC_DRIVER_MINOR_VERSION 1
-#define AAC_DRIVER_BUGFIX_LEVEL 14
+#define AAC_DRIVER_BUGFIX_LEVEL 15
#define AAC_DRIVER_TYPE AAC_TYPE_RELEASE
#define STR(s) # s
@@ -202,6 +202,8 @@ struct aac_fib_context {
struct aac_fib_context *next, *prev;
};
+typedef void (*aac_cmd_fib_t)(struct aac_softstate *, struct aac_cmd *, int);
+
#define AAC_VENDOR_LEN 8
#define AAC_PRODUCT_LEN 16
@@ -218,6 +220,7 @@ struct aac_softstate {
int flags; /* firmware features enabled */
int instance;
dev_info_t *devinfo_p;
+ int slen;
/* DMA attributes */
ddi_dma_attr_t buf_dma_attr;
@@ -248,6 +251,8 @@ struct aac_softstate {
uint32_t aac_sg_tablesize; /* max. sg count from host */
uint32_t aac_max_sectors; /* max. I/O size from host (blocks) */
+ aac_cmd_fib_t aac_cmd_fib; /* IO cmd FIB construct function */
+
ddi_iblock_cookie_t iblock_cookie;
ddi_softintr_t softint_id; /* soft intr */
@@ -305,25 +310,20 @@ struct aac_softstate {
/* aac_cmd flags */
#define AAC_CMD_CONSISTENT (1 << 0)
#define AAC_CMD_DMA_PARTIAL (1 << 1)
-#define AAC_CMD_DMA_VALID (1 << 3)
-#define AAC_CMD_BUF_READ (1 << 4)
-#define AAC_CMD_BUF_WRITE (1 << 5)
-#define AAC_CMD_SOFT_INTR (1 << 6) /* poll IO */
-#define AAC_CMD_NO_INTR (1 << 7) /* no interrupt to sd */
-#define AAC_CMD_HARD_INTR (1 << 8) /* interrupt IO */
+#define AAC_CMD_DMA_VALID (1 << 2)
+#define AAC_CMD_BUF_READ (1 << 3)
+#define AAC_CMD_BUF_WRITE (1 << 4)
+#define AAC_CMD_SYNC (1 << 5) /* use sync FIB */
+#define AAC_CMD_NO_INTR (1 << 6) /* poll IO, no intr to sd */
+#define AAC_CMD_CMPLT (1 << 7)
+#define AAC_CMD_ABORT (1 << 8)
#define AAC_CMD_TIMEOUT (1 << 9)
-/* aac_cmd states */
-#define AAC_CMD_INCMPLT 0
-#define AAC_CMD_CMPLT 1
-#define AAC_CMD_ABORT 2
-
struct aac_cmd {
struct aac_cmd *next;
struct scsi_pkt *pkt;
int cmdlen;
int flags;
- int state;
time_t start_time; /* time when the cmd is sent to the adapter */
time_t timeout; /* max time in seconds for cmd to complete */
struct buf *bp;
@@ -339,13 +339,19 @@ struct aac_cmd {
uint_t cur_win;
uint_t total_nwin;
size_t total_xfer;
+ uint64_t blkno;
+ uint32_t bcount; /* buffer size in byte */
+
+ /* Call back function for completed command */
+ void (*ac_comp)(struct aac_softstate *, struct aac_cmd *);
+
struct aac_slot *slotp; /* slot used by this command */
+ struct aac_container *dvp; /* target device */
- /*
- * NOTE: should be the last field, because New Comm. FIBs may
- * take more space than sizeof (struct aac_fib).
- */
- struct aac_fib fib; /* FIB for this IO command */
+ /* FIB for this IO command */
+ int fib_kmsz; /* size of kmem_alloc'ed FIB */
+ int fib_size; /* size of the FIB xferred to/from the card */
+ struct aac_fib *fibp;
};
#ifdef DEBUG
diff --git a/usr/src/uts/intel/io/aac/aac_ioctl.c b/usr/src/uts/intel/io/aac/aac_ioctl.c
index 25929acb58..cced8a9cc9 100644
--- a/usr/src/uts/intel/io/aac/aac_ioctl.c
+++ b/usr/src/uts/intel/io/aac/aac_ioctl.c
@@ -56,7 +56,9 @@
*/
extern int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t *);
-extern int aac_do_async_io(struct aac_softstate *, struct aac_cmd *);
+extern int aac_do_io(struct aac_softstate *, struct aac_cmd *);
+extern void aac_free_dmamap(struct aac_cmd *);
+extern void aac_ioctl_complete(struct aac_softstate *, struct aac_cmd *);
extern ddi_device_acc_attr_t aac_acc_attr;
@@ -159,44 +161,74 @@ aac_check_revision(struct aac_softstate *softs, intptr_t arg, int mode)
}
static int
+aac_send_fib(struct aac_softstate *softs, struct aac_cmd *acp)
+{
+ int rval;
+
+ acp->flags |= AAC_CMD_NO_INTR | AAC_CMD_SYNC;
+ acp->ac_comp = aac_ioctl_complete;
+ acp->timeout = AAC_IOCTL_TIMEOUT;
+ acp->dvp = NULL;
+
+ if (softs->state == AAC_STATE_DEAD)
+ return (ENXIO);
+
+ rw_enter(&softs->errlock, RW_READER);
+ rval = aac_do_io(softs, acp);
+ if (rval == TRAN_ACCEPT) {
+ rval = 0;
+ } else if (rval == TRAN_BADPKT) {
+ AACDB_PRINT(softs, CE_CONT, "User SendFib failed ENXIO");
+ rval = ENXIO;
+ } else if (rval == TRAN_BUSY) {
+ AACDB_PRINT(softs, CE_CONT, "User SendFib failed EBUSY");
+ rval = EBUSY;
+ }
+ rw_exit(&softs->errlock);
+
+ return (rval);
+}
+
+static int
aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode)
{
int hbalen;
struct aac_cmd *acp;
struct aac_fib *fibp;
- unsigned size;
+ unsigned fib_size;
int rval = 0;
DBCALLED(softs, 2);
- if (softs->state == AAC_STATE_DEAD)
- return (ENXIO);
-
/* Copy in FIB header */
- hbalen = sizeof (struct aac_cmd) - sizeof (struct aac_fib) +
- softs->aac_max_fib_size;
+ hbalen = sizeof (struct aac_cmd) + softs->aac_max_fib_size;
if ((acp = kmem_zalloc(hbalen, KM_NOSLEEP)) == NULL)
return (ENOMEM);
- fibp = &acp->fib;
+ fibp = (struct aac_fib *)(acp + 1);
+ acp->fibp = fibp;
if (ddi_copyin((void *)arg, fibp,
sizeof (struct aac_fib_header), mode) != 0) {
rval = EFAULT;
goto finish;
}
- size = fibp->Header.Size + sizeof (struct aac_fib_header);
- if (size < fibp->Header.SenderSize)
- size = fibp->Header.SenderSize;
- if (size > softs->aac_max_fib_size) {
+
+ fib_size = fibp->Header.Size + sizeof (struct aac_fib_header);
+ if (fib_size < fibp->Header.SenderSize)
+ fib_size = fibp->Header.SenderSize;
+ if (fib_size > softs->aac_max_fib_size) {
rval = EFAULT;
goto finish;
}
/* Copy in FIB data */
- if (ddi_copyin((void *)arg, fibp, size, mode) != 0) {
+ if (ddi_copyin(((struct aac_fib *)arg)->data, fibp->data,
+ fibp->Header.Size, mode) != 0) {
rval = EFAULT;
goto finish;
}
+ acp->fib_size = fib_size;
+ fibp->Header.Size = fib_size;
AACDB_PRINT_FIB(softs, fibp);
@@ -209,38 +241,18 @@ aac_ioctl_send_fib(struct aac_softstate *softs, intptr_t arg, int mode)
ASSERT(!(fibp->Header.XferState & AAC_FIBSTATE_ASYNC));
fibp->Header.XferState |=
(AAC_FIBSTATE_FROMHOST | AAC_FIBSTATE_REXPECTED);
- fibp->Header.Size = size;
- acp->flags = AAC_CMD_HARD_INTR;
- acp->state = AAC_CMD_INCMPLT;
-
- /* Send FIB */
- rw_enter(&softs->errlock, RW_READER);
- if (aac_do_async_io(softs, acp) != AACOK) {
- AACDB_PRINT(softs, CE_CONT, "User SendFib failed");
- rval = ENXIO;
- }
- rw_exit(&softs->errlock);
- if (rval != 0)
+ if ((rval = aac_send_fib(softs, acp)) != 0)
goto finish;
-
- /* Wait FIB to complete */
- mutex_enter(&softs->event_mutex);
- while (acp->state == AAC_CMD_INCMPLT)
- cv_wait(&softs->event, &softs->event_mutex);
- if (acp->state == AAC_CMD_ABORT)
- rval = EBUSY;
- mutex_exit(&softs->event_mutex);
}
- if (rval == 0) {
- if (ddi_copyout(fibp, (void *)arg,
- fibp->Header.Size, mode) != 0) {
- rval = EFAULT;
- goto finish;
- }
+ if (ddi_copyout(fibp, (void *)arg, acp->fib_size, mode) != 0) {
+ AACDB_PRINT(softs, CE_CONT, "FIB copyout failed");
+ rval = EFAULT;
+ goto finish;
}
+ rval = 0;
finish:
kmem_free(acp, hbalen);
return (rval);
@@ -372,69 +384,74 @@ aac_send_raw_srb(struct aac_softstate *softs, intptr_t arg, int mode)
int hbalen;
struct aac_cmd *acp;
struct aac_fib *fibp;
- struct aac_srb *srbcmd;
- struct aac_srb *user_srb = (struct aac_srb *)arg;
- struct aac_srb_reply *srbreply;
- void *user_reply;
- uint32_t byte_count = 0, fibsize = 0;
- uint_t i, dma_flags = DDI_DMA_CONSISTENT;
- ddi_dma_cookie_t *cookiep = NULL;
- int err, rval = 0;
+ struct aac_srb *srb;
+ uint32_t usr_fib_size;
+ uint_t dma_flags = DDI_DMA_CONSISTENT;
+ struct aac_sg_entry *sgp;
+ struct aac_sg_entry64 *sg64p;
+ uint32_t fib_size;
+ uint32_t srb_sg_bytecount;
+ uint64_t srb_sg_address;
+ int rval;
DBCALLED(softs, 2);
- if (softs->state == AAC_STATE_DEAD)
- return (ENXIO);
-
- hbalen = sizeof (struct aac_cmd) - sizeof (struct aac_fib) +
- softs->aac_max_fib_size;
+ hbalen = sizeof (struct aac_cmd) + softs->aac_max_fib_size;
if ((acp = kmem_zalloc(hbalen, KM_NOSLEEP)) == NULL)
return (ENOMEM);
- fibp = &acp->fib;
- srbcmd = (struct aac_srb *)fibp->data;
+ fibp = (struct aac_fib *)(acp + 1);
+ acp->fibp = fibp;
+ srb = (struct aac_srb *)fibp->data;
/* Read srb size */
- if (ddi_copyin((void *)&user_srb->count, &fibsize,
+ if (ddi_copyin(&((struct aac_srb *)arg)->count, &usr_fib_size,
sizeof (uint32_t), mode) != 0) {
rval = EFAULT;
goto finish;
}
- if (fibsize > (softs->aac_max_fib_size - \
+ if (usr_fib_size > (softs->aac_max_fib_size - \
sizeof (struct aac_fib_header))) {
rval = EINVAL;
goto finish;
}
/* Copy in srb */
- if (ddi_copyin((void *)user_srb, srbcmd, fibsize, mode) != 0) {
+ if (ddi_copyin((void *)arg, srb, usr_fib_size, mode) != 0) {
rval = EFAULT;
goto finish;
}
- srbcmd->function = 0; /* SRBF_ExecuteScsi */
- srbcmd->retry_limit = 0; /* obsolete */
+
+ srb->function = 0; /* SRBF_ExecuteScsi */
+ srb->retry_limit = 0; /* obsolete */
/* Only one sg element from userspace supported */
- if (srbcmd->sg.SgCount > 1) {
+ if (srb->sg.SgCount > 1) {
rval = EINVAL;
+ AACDB_PRINT(softs, CE_NOTE, "srb->sg.SgCount %d >1",
+ srb->sg.SgCount);
goto finish;
}
+
/* Check FIB size */
- if (fibsize != (sizeof (struct aac_srb) + \
- (srbcmd->sg.SgCount - 1) * sizeof (struct aac_sg_entry))) {
+ sgp = srb->sg.SgEntry;
+ sg64p = (struct aac_sg_entry64 *)sgp;
+ if (usr_fib_size != (sizeof (struct aac_srb) + \
+ (srb->sg.SgCount - 1) * sizeof (struct aac_sg_entry))) {
rval = EINVAL;
goto finish;
}
- user_reply = (char *)arg + fibsize;
+ srb_sg_bytecount = sgp->SgByteCount;
+ srb_sg_address = (uint64_t)sgp->SgAddress;
/* Allocate and bind DMA memory space */
acp->buf_dma_handle = NULL;
acp->abh = NULL;
acp->left_cookien = 0;
- err = ddi_dma_alloc_handle(softs->devinfo_p, &softs->buf_dma_attr,
+ rval = ddi_dma_alloc_handle(softs->devinfo_p, &softs->buf_dma_attr,
DDI_DMA_DONTWAIT, NULL, &acp->buf_dma_handle);
- if (err != DDI_SUCCESS) {
+ if (rval != DDI_SUCCESS) {
AACDB_PRINT(softs, CE_WARN,
"Can't allocate DMA handle, errno=%d", rval);
rval = EFAULT;
@@ -442,94 +459,63 @@ aac_send_raw_srb(struct aac_softstate *softs, intptr_t arg, int mode)
}
/* TODO: remove duplicate code with aac_tran_init_pkt() */
- if (srbcmd->sg.SgCount == 1) {
+ if (srb->sg.SgCount == 1 && srb_sg_bytecount != 0) {
size_t bufsz;
- err = ddi_dma_mem_alloc(acp->buf_dma_handle,
- AAC_ROUNDUP(srbcmd->sg.SgEntry[0].SgByteCount,
- AAC_DMA_ALIGN),
+ /* Allocate DMA buffer */
+ rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
+ AAC_ROUNDUP(srb_sg_bytecount, AAC_DMA_ALIGN),
&aac_acc_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT,
NULL, &acp->abp, &bufsz, &acp->abh);
- if (err != DDI_SUCCESS) {
+ if (rval != DDI_SUCCESS) {
AACDB_PRINT(softs, CE_NOTE,
"Cannot alloc DMA to non-aligned buf");
rval = ENOMEM;
goto finish;
}
- if ((srbcmd->flags & (SRB_DataIn | SRB_DataOut)) ==
+ if ((srb->flags & (SRB_DataIn | SRB_DataOut)) ==
(SRB_DataIn | SRB_DataOut))
dma_flags |= DDI_DMA_RDWR;
- else if ((srbcmd->flags & (SRB_DataIn | SRB_DataOut)) ==
+ else if ((srb->flags & (SRB_DataIn | SRB_DataOut)) ==
SRB_DataIn)
dma_flags |= DDI_DMA_READ;
- else if ((srbcmd->flags & (SRB_DataIn | SRB_DataOut)) ==
+ else if ((srb->flags & (SRB_DataIn | SRB_DataOut)) ==
SRB_DataOut)
dma_flags |= DDI_DMA_WRITE;
- err = ddi_dma_addr_bind_handle(acp->buf_dma_handle, NULL,
+
+ rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle, NULL,
acp->abp, bufsz, dma_flags, DDI_DMA_DONTWAIT, 0,
&acp->cookie, &acp->left_cookien);
- if (err != DDI_DMA_MAPPED) {
+ if (rval != DDI_DMA_MAPPED) {
AACDB_PRINT(softs, CE_NOTE, "Cannot bind buf for DMA");
rval = EFAULT;
goto finish;
}
- cookiep = &acp->cookie;
+ acp->flags |= AAC_CMD_DMA_VALID;
- if (srbcmd->flags & SRB_DataOut) {
- if (ddi_copyin(
+ /* Copy in user srb buf content */
+ if ((srb->flags & SRB_DataOut) &&
+ (ddi_copyin(
#ifdef _LP64
- (void *)(uint64_t)user_srb-> \
- sg.SgEntry[0].SgAddress,
+ (void *)srb_sg_address,
#else
- (void *)user_srb->sg.SgEntry[0].SgAddress,
+ (void *)(uint32_t)srb_sg_address,
#endif
- acp->abp, user_srb->sg.SgEntry[0].SgByteCount,
- mode) != 0) {
- rval = EFAULT;
- goto finish;
- }
+ acp->abp, srb_sg_bytecount, mode) != 0)) {
+ rval = EFAULT;
+ goto finish;
}
}
- /* Fill in command, sg elements */
- if (softs->flags & AAC_FLAGS_SG_64BIT) {
- struct aac_sg_entry64 *sgp = (struct aac_sg_entry64 *)
- srbcmd->sg.SgEntry;
-
- fibp->Header.Command = ScsiPortCommandU64;
- for (i = 0; i < acp->left_cookien &&
- i < softs->aac_sg_tablesize; i++) {
- sgp[i].SgAddress = cookiep->dmac_laddress;
- sgp[i].SgByteCount = cookiep->dmac_size;
- if ((i + 1) < acp->left_cookien)
- ddi_dma_nextcookie(acp->buf_dma_handle,
- cookiep);
- byte_count += sgp[i].SgByteCount;
- }
- fibsize = sizeof (struct aac_srb) - \
- sizeof (struct aac_sg_entry) + \
- i * sizeof (struct aac_sg_entry64);
- } else {
- struct aac_sg_entry *sgp = srbcmd->sg.SgEntry;
-
- fibp->Header.Command = ScsiPortCommand;
- for (i = 0; i < acp->left_cookien &&
- i < softs->aac_sg_tablesize; i++) {
- sgp[i].SgAddress = cookiep->dmac_laddress;
- sgp[i].SgByteCount = cookiep->dmac_size;
- if ((i + 1) < acp->left_cookien)
- ddi_dma_nextcookie(acp->buf_dma_handle,
- cookiep);
- byte_count += sgp[i].SgByteCount;
- }
- fibsize = sizeof (struct aac_srb) + \
- (i - 1) * sizeof (struct aac_sg_entry);
+ if (acp->left_cookien > softs->aac_sg_tablesize) {
+ AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d\n",
+ acp->left_cookien);
+ rval = EFAULT;
+ goto finish;
}
- srbcmd->count = byte_count;
- srbcmd->sg.SgCount = i;
- /* Fill fib header */
+ /* Init FIB header */
fibp->Header.XferState =
AAC_FIBSTATE_HOSTOWNED |
AAC_FIBSTATE_INITIALISED |
@@ -537,64 +523,76 @@ aac_send_raw_srb(struct aac_softstate *softs, intptr_t arg, int mode)
AAC_FIBSTATE_FROMHOST |
AAC_FIBSTATE_REXPECTED |
AAC_FIBSTATE_NORM;
- fibp->Header.Size = sizeof (struct aac_fib_header) + fibsize;
fibp->Header.StructType = AAC_FIBTYPE_TFIB;
fibp->Header.SenderSize = softs->aac_max_fib_size;
- /* TODO: remove duplicate code with aac_ioctl_send_fib() */
- AACDB_PRINT_FIB(softs, fibp);
-
- /* Send command */
- acp->flags = AAC_CMD_HARD_INTR;
- acp->state = AAC_CMD_INCMPLT;
+ fib_size = sizeof (struct aac_fib_header) + \
+ sizeof (struct aac_srb) - sizeof (struct aac_sg_entry);
- rw_enter(&softs->errlock, RW_READER);
- if (aac_do_async_io(softs, acp) != AACOK) {
- AACDB_PRINT(softs, CE_CONT, "User SendFib failed");
- rval = ENXIO;
+ /* Calculate FIB data size */
+ if (softs->flags & AAC_FLAGS_SG_64BIT) {
+ fibp->Header.Command = ScsiPortCommandU64;
+ fib_size += acp->left_cookien * sizeof (struct aac_sg_entry64);
+ } else {
+ fibp->Header.Command = ScsiPortCommand;
+ fib_size += acp->left_cookien * sizeof (struct aac_sg_entry);
}
- rw_exit(&softs->errlock);
- if (rval != 0)
- goto finish;
+ fibp->Header.Size = fib_size;
- mutex_enter(&softs->event_mutex);
- while (acp->state == AAC_CMD_INCMPLT)
- cv_wait(&softs->event, &softs->event_mutex);
- if (acp->state == AAC_CMD_ABORT)
- rval = EBUSY;
- mutex_exit(&softs->event_mutex);
- if (rval != 0)
+ /* Fill in sg elements */
+ srb->sg.SgCount = acp->left_cookien;
+ acp->bcount = 0;
+ do {
+ if (softs->flags & AAC_FLAGS_SG_64BIT) {
+ sg64p->SgAddress = acp->cookie.dmac_laddress;
+ sg64p->SgByteCount = acp->cookie.dmac_size;
+ sg64p++;
+ } else {
+ sgp->SgAddress = acp->cookie.dmac_laddress;
+ sgp->SgByteCount = acp->cookie.dmac_size;
+ sgp++;
+ }
+
+ acp->bcount += acp->cookie.dmac_size;
+ acp->left_cookien--;
+ if (acp->left_cookien > 0)
+ ddi_dma_nextcookie(acp->buf_dma_handle,
+ &acp->cookie);
+ else
+ break;
+ /*CONSTCOND*/
+ } while (1);
+
+ /* Send FIB command */
+ AACDB_PRINT_FIB(softs, fibp);
+ acp->fib_size = fib_size;
+ if ((rval = aac_send_fib(softs, acp)) != 0)
goto finish;
- if ((srbcmd->sg.SgCount == 1) && (srbcmd->flags & SRB_DataIn)) {
- if (ddi_copyout(acp->abp,
+ if ((srb->sg.SgCount == 1) && (srb->flags & SRB_DataIn) &&
+ (ddi_copyout(acp->abp,
#ifdef _LP64
- (void *)(uint64_t)user_srb->sg.SgEntry[0].SgAddress,
+ (void *)srb_sg_address,
#else
- (void *)user_srb->sg.SgEntry[0].SgAddress,
+ (void *)(uint32_t)srb_sg_address,
#endif
- user_srb->sg.SgEntry[0].SgByteCount, mode) != 0) {
- rval = EFAULT;
- goto finish;
- }
+ srb_sg_bytecount, mode) != 0)) {
+ rval = EFAULT;
+ goto finish;
}
/* Status struct */
- srbreply = (struct aac_srb_reply *)fibp->data;
- if (ddi_copyout(srbreply, user_reply,
+ if (ddi_copyout((struct aac_srb_reply *)fibp->data,
+ ((uint8_t *)arg + usr_fib_size),
sizeof (struct aac_srb_reply), mode) != 0) {
rval = EFAULT;
goto finish;
}
+ rval = 0;
finish:
- if (cookiep)
- (void) ddi_dma_unbind_handle(acp->buf_dma_handle);
- if (acp->abh)
- ddi_dma_mem_free(&acp->abh);
- if (acp->buf_dma_handle)
- ddi_dma_free_handle(&acp->buf_dma_handle);
+ aac_free_dmamap(acp);
kmem_free(acp, hbalen);
return (rval);
}
diff --git a/usr/src/uts/intel/io/aac/aac_regs.h b/usr/src/uts/intel/io/aac/aac_regs.h
index 4f391382cd..ce5cbd00bc 100644
--- a/usr/src/uts/intel/io/aac/aac_regs.h
+++ b/usr/src/uts/intel/io/aac/aac_regs.h
@@ -649,7 +649,7 @@ typedef enum {
CT_SET_CACHE_SYNC_MODE, /* 211 */
CT_LAST_COMMAND /* last command */
-} AAC_CtCommand;
+} AAC_CTCommand;
/* General return status */
#define CT_OK 218
@@ -711,6 +711,46 @@ struct aac_pause_command {
};
/*
+ * Command status values
+ */
+typedef enum {
+ ST_OK = 0,
+ ST_PERM = 1,
+ ST_NOENT = 2,
+ ST_IO = 5,
+ ST_NXIO = 6,
+ ST_E2BIG = 7,
+ ST_ACCES = 13,
+ ST_EXIST = 17,
+ ST_XDEV = 18,
+ ST_NODEV = 19,
+ ST_NOTDIR = 20,
+ ST_ISDIR = 21,
+ ST_INVAL = 22,
+ ST_FBIG = 27,
+ ST_NOSPC = 28,
+ ST_ROFS = 30,
+ ST_MLINK = 31,
+ ST_WOULDBLOCK = 35,
+ ST_NAMETOOLONG = 63,
+ ST_NOTEMPTY = 66,
+ ST_DQUOT = 69,
+ ST_STALE = 70,
+ ST_REMOTE = 71,
+ ST_BADHANDLE = 10001,
+ ST_NOT_SYNC = 10002,
+ ST_BAD_COOKIE = 10003,
+ ST_NOTSUPP = 10004,
+ ST_TOOSMALL = 10005,
+ ST_SERVERFAULT = 10006,
+ ST_BADTYPE = 10007,
+ ST_JUKEBOX = 10008,
+ ST_NOTMOUNTED = 10009,
+ ST_MAINTMODE = 10010,
+ ST_STALEACL = 10011
+} AAC_FSAStatus;
+
+/*
* Object-Server / Volume-Manager Dispatch Classes
*/
typedef enum {
@@ -737,7 +777,7 @@ typedef enum {
VM_CtHostWrite64,
VM_NameServe64 = 22,
MAX_VMCOMMAND_NUM /* used for sizing stats array - leave last */
-} AAC_VmCommand;
+} AAC_VMCommand;
/*
* Host-addressable object types
@@ -819,6 +859,11 @@ struct aac_blockread64 {
struct aac_sg_table64 SgMap64;
};
+struct aac_blockread_response {
+ uint32_t Status;
+ uint32_t ByteCount;
+};
+
struct aac_blockwrite {
uint32_t Command;
uint32_t ContainerId;
@@ -838,6 +883,12 @@ struct aac_blockwrite64 {
struct aac_sg_table64 SgMap64;
};
+struct aac_blockwrite_response {
+ uint32_t Status;
+ uint32_t ByteCount;
+ uint32_t Committed;
+};
+
struct aac_raw_io {
uint64_t BlockNumber;
uint32_t ByteCount;
@@ -1294,7 +1345,7 @@ typedef enum {
/* last command */
CL_LAST_COMMAND /* used for bounds checking */
-} AAC_ClCommand;
+} AAC_CLCommand;
/*
* Disk IOCTL Functions