15678Spl196000 /*
2*12408SZhongyan.Gu@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
35678Spl196000 */
45678Spl196000
55678Spl196000 /*
67567SXin.Chen@Sun.COM * Copyright 2005-08 Adaptec, Inc.
77567SXin.Chen@Sun.COM * Copyright (c) 2005-08 Adaptec Inc., Achim Leubner
85678Spl196000 * Copyright (c) 2000 Michael Smith
95678Spl196000 * Copyright (c) 2001 Scott Long
105678Spl196000 * Copyright (c) 2000 BSDi
115678Spl196000 * All rights reserved.
125678Spl196000 *
135678Spl196000 * Redistribution and use in source and binary forms, with or without
145678Spl196000 * modification, are permitted provided that the following conditions
155678Spl196000 * are met:
165678Spl196000 * 1. Redistributions of source code must retain the above copyright
175678Spl196000 * notice, this list of conditions and the following disclaimer.
185678Spl196000 * 2. Redistributions in binary form must reproduce the above copyright
195678Spl196000 * notice, this list of conditions and the following disclaimer in the
205678Spl196000 * documentation and/or other materials provided with the distribution.
215678Spl196000 *
225678Spl196000 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
235678Spl196000 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
245678Spl196000 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
255678Spl196000 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
265678Spl196000 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
275678Spl196000 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
285678Spl196000 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
295678Spl196000 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
305678Spl196000 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
315678Spl196000 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
325678Spl196000 * SUCH DAMAGE.
335678Spl196000 */
345678Spl196000 #include <sys/modctl.h>
355678Spl196000 #include <sys/conf.h>
365678Spl196000 #include <sys/cmn_err.h>
375678Spl196000 #include <sys/ddi.h>
385678Spl196000 #include <sys/devops.h>
395678Spl196000 #include <sys/pci.h>
405678Spl196000 #include <sys/types.h>
415678Spl196000 #include <sys/ddidmareq.h>
425678Spl196000 #include <sys/scsi/scsi.h>
435678Spl196000 #include <sys/ksynch.h>
445678Spl196000 #include <sys/sunddi.h>
455678Spl196000 #include <sys/byteorder.h>
465678Spl196000 #include "aac_regs.h"
475678Spl196000 #include "aac.h"
485678Spl196000
495678Spl196000 /*
505678Spl196000 * FMA header files
515678Spl196000 */
525678Spl196000 #include <sys/ddifm.h>
535678Spl196000 #include <sys/fm/protocol.h>
545678Spl196000 #include <sys/fm/util.h>
555678Spl196000 #include <sys/fm/io/ddi.h>
565678Spl196000
575678Spl196000 /*
585678Spl196000 * For minor nodes created by the SCSA framework, minor numbers are
595678Spl196000 * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a
605678Spl196000 * number less than 64.
615678Spl196000 *
625678Spl196000 * To support cfgadm, need to confirm the SCSA framework by creating
635678Spl196000 * devctl/scsi and driver specific minor nodes under SCSA format,
645678Spl196000 * and calling scsi_hba_xxx() functions aacordingly.
655678Spl196000 */
665678Spl196000
675678Spl196000 #define AAC_MINOR 32
685678Spl196000 #define INST2AAC(x) (((x) << INST_MINOR_SHIFT) | AAC_MINOR)
695678Spl196000 #define AAC_SCSA_MINOR(x) ((x) & TRAN_MINOR_MASK)
705678Spl196000 #define AAC_IS_SCSA_NODE(x) ((x) == DEVCTL_MINOR || (x) == SCSI_MINOR)
715678Spl196000
727567SXin.Chen@Sun.COM #define SD2TRAN(sd) ((sd)->sd_address.a_hba_tran)
735678Spl196000 #define AAC_TRAN2SOFTS(tran) ((struct aac_softstate *)(tran)->tran_hba_private)
745678Spl196000 #define AAC_DIP2TRAN(dip) ((scsi_hba_tran_t *)ddi_get_driver_private(dip))
755678Spl196000 #define AAC_DIP2SOFTS(dip) (AAC_TRAN2SOFTS(AAC_DIP2TRAN(dip)))
767567SXin.Chen@Sun.COM #define SD2AAC(sd) (AAC_TRAN2SOFTS(SD2TRAN(sd)))
777567SXin.Chen@Sun.COM #define AAC_PD(t) ((t) - AAC_MAX_LD)
787567SXin.Chen@Sun.COM #define AAC_DEV(softs, t) (((t) < AAC_MAX_LD) ? \
797567SXin.Chen@Sun.COM &(softs)->containers[(t)].dev : \
807567SXin.Chen@Sun.COM ((t) < AAC_MAX_DEV(softs)) ? \
817567SXin.Chen@Sun.COM &(softs)->nondasds[AAC_PD(t)].dev : NULL)
827567SXin.Chen@Sun.COM #define AAC_DEVCFG_BEGIN(softs, tgt) \
837567SXin.Chen@Sun.COM aac_devcfg((softs), (tgt), 1)
847567SXin.Chen@Sun.COM #define AAC_DEVCFG_END(softs, tgt) \
857567SXin.Chen@Sun.COM aac_devcfg((softs), (tgt), 0)
865678Spl196000 #define PKT2AC(pkt) ((struct aac_cmd *)(pkt)->pkt_ha_private)
875678Spl196000 #define AAC_BUSYWAIT(cond, timeout /* in millisecond */) { \
885678Spl196000 if (!(cond)) { \
895678Spl196000 int count = (timeout) * 10; \
905678Spl196000 while (count) { \
915678Spl196000 drv_usecwait(100); \
925678Spl196000 if (cond) \
935678Spl196000 break; \
945678Spl196000 count--; \
955678Spl196000 } \
965678Spl196000 (timeout) = (count + 9) / 10; \
975678Spl196000 } \
985678Spl196000 }
995678Spl196000
1005678Spl196000 #define AAC_SENSE_DATA_DESCR_LEN \
1015678Spl196000 (sizeof (struct scsi_descr_sense_hdr) + \
1025678Spl196000 sizeof (struct scsi_information_sense_descr))
1035678Spl196000 #define AAC_ARQ64_LENGTH \
1045678Spl196000 (sizeof (struct scsi_arq_status) + \
1055678Spl196000 AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
1065678Spl196000
1075678Spl196000 /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
1085678Spl196000 #define AAC_GETGXADDR(cmdlen, cdbp) \
1095678Spl196000 ((cmdlen == 6) ? GETG0ADDR(cdbp) : \
1105678Spl196000 (cmdlen == 10) ? (uint32_t)GETG1ADDR(cdbp) : \
1115678Spl196000 ((uint64_t)GETG4ADDR(cdbp) << 32) | (uint32_t)GETG4ADDRTL(cdbp))
1125678Spl196000
1135678Spl196000 #define AAC_CDB_INQUIRY_CMDDT 0x02
1145678Spl196000 #define AAC_CDB_INQUIRY_EVPD 0x01
1155678Spl196000 #define AAC_VPD_PAGE_CODE 1
1165678Spl196000 #define AAC_VPD_PAGE_LENGTH 3
1175678Spl196000 #define AAC_VPD_PAGE_DATA 4
1185678Spl196000 #define AAC_VPD_ID_CODESET 0
1195678Spl196000 #define AAC_VPD_ID_TYPE 1
1205678Spl196000 #define AAC_VPD_ID_LENGTH 3
1215678Spl196000 #define AAC_VPD_ID_DATA 4
1225678Spl196000
1237567SXin.Chen@Sun.COM #define AAC_SCSI_RPTLUNS_HEAD_SIZE 0x08
1247567SXin.Chen@Sun.COM #define AAC_SCSI_RPTLUNS_ADDR_SIZE 0x08
1257567SXin.Chen@Sun.COM #define AAC_SCSI_RPTLUNS_ADDR_MASK 0xC0
1267567SXin.Chen@Sun.COM /* 00b - peripheral device addressing method */
1277567SXin.Chen@Sun.COM #define AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL 0x00
1287567SXin.Chen@Sun.COM /* 01b - flat space addressing method */
1297567SXin.Chen@Sun.COM #define AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE 0x40
1307567SXin.Chen@Sun.COM /* 10b - logical unit addressing method */
1317567SXin.Chen@Sun.COM #define AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT 0x80
1327567SXin.Chen@Sun.COM
1335678Spl196000 /* Return the size of FIB with data part type data_type */
1345678Spl196000 #define AAC_FIB_SIZEOF(data_type) \
1355678Spl196000 (sizeof (struct aac_fib_header) + sizeof (data_type))
1365678Spl196000 /* Return the container size defined in mir */
1375678Spl196000 #define AAC_MIR_SIZE(softs, acc, mir) \
1385678Spl196000 (((softs)->flags & AAC_FLAGS_LBA_64BIT) ? \
1395678Spl196000 (uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity) + \
1405678Spl196000 ((uint64_t)ddi_get32((acc), &(mir)->MntObj.CapacityHigh) << 32) : \
1415678Spl196000 (uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity))
1425678Spl196000
1435678Spl196000 /* The last entry of aac_cards[] is for unknown cards */
1445678Spl196000 #define AAC_UNKNOWN_CARD \
1455678Spl196000 (sizeof (aac_cards) / sizeof (struct aac_card_type) - 1)
1465678Spl196000 #define CARD_IS_UNKNOWN(i) (i == AAC_UNKNOWN_CARD)
1475678Spl196000 #define BUF_IS_READ(bp) ((bp)->b_flags & B_READ)
1485678Spl196000 #define AAC_IS_Q_EMPTY(q) ((q)->q_head == NULL)
1495678Spl196000 #define AAC_CMDQ(acp) (!((acp)->flags & AAC_CMD_SYNC))
1505678Spl196000
1515678Spl196000 #define PCI_MEM_GET32(softs, off) \
1525678Spl196000 ddi_get32((softs)->pci_mem_handle, \
1537100Spl196000 (void *)((softs)->pci_mem_base_vaddr + (off)))
1545678Spl196000 #define PCI_MEM_PUT32(softs, off, val) \
1555678Spl196000 ddi_put32((softs)->pci_mem_handle, \
1567100Spl196000 (void *)((softs)->pci_mem_base_vaddr + (off)), \
1575678Spl196000 (uint32_t)(val))
1585678Spl196000 #define PCI_MEM_GET16(softs, off) \
1595678Spl196000 ddi_get16((softs)->pci_mem_handle, \
1607100Spl196000 (void *)((softs)->pci_mem_base_vaddr + (off)))
1615678Spl196000 #define PCI_MEM_PUT16(softs, off, val) \
1625678Spl196000 ddi_put16((softs)->pci_mem_handle, \
1637100Spl196000 (void *)((softs)->pci_mem_base_vaddr + (off)), (uint16_t)(val))
1645678Spl196000 /* Write host data at valp to device mem[off] repeatedly count times */
1655678Spl196000 #define PCI_MEM_REP_PUT8(softs, off, valp, count) \
1665678Spl196000 ddi_rep_put8((softs)->pci_mem_handle, (uint8_t *)(valp), \
1675678Spl196000 (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
1685678Spl196000 count, DDI_DEV_AUTOINCR)
1695678Spl196000 /* Read device data at mem[off] to host addr valp repeatedly count times */
1705678Spl196000 #define PCI_MEM_REP_GET8(softs, off, valp, count) \
1715678Spl196000 ddi_rep_get8((softs)->pci_mem_handle, (uint8_t *)(valp), \
1725678Spl196000 (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
1735678Spl196000 count, DDI_DEV_AUTOINCR)
1745678Spl196000 #define AAC_GET_FIELD8(acc, d, s, field) \
1755678Spl196000 (d)->field = ddi_get8(acc, (uint8_t *)&(s)->field)
1765678Spl196000 #define AAC_GET_FIELD32(acc, d, s, field) \
1775678Spl196000 (d)->field = ddi_get32(acc, (uint32_t *)&(s)->field)
1785678Spl196000 #define AAC_GET_FIELD64(acc, d, s, field) \
1795678Spl196000 (d)->field = ddi_get64(acc, (uint64_t *)&(s)->field)
1805678Spl196000 #define AAC_REP_GET_FIELD8(acc, d, s, field, r) \
1815678Spl196000 ddi_rep_get8((acc), (uint8_t *)&(d)->field, \
1825678Spl196000 (uint8_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
1835678Spl196000 #define AAC_REP_GET_FIELD32(acc, d, s, field, r) \
1845678Spl196000 ddi_rep_get32((acc), (uint32_t *)&(d)->field, \
1855678Spl196000 (uint32_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
1865678Spl196000
1875678Spl196000 #define AAC_ENABLE_INTR(softs) { \
1885678Spl196000 if (softs->flags & AAC_FLAGS_NEW_COMM) \
1895678Spl196000 PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_NEW); \
1905678Spl196000 else \
1915678Spl196000 PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_BITS); \
19211636SXin.Chen@Sun.COM softs->state |= AAC_STATE_INTR; \
19311636SXin.Chen@Sun.COM }
19411636SXin.Chen@Sun.COM
19511636SXin.Chen@Sun.COM #define AAC_DISABLE_INTR(softs) { \
19611636SXin.Chen@Sun.COM PCI_MEM_PUT32(softs, AAC_OIMR, ~0); \
19711636SXin.Chen@Sun.COM softs->state &= ~AAC_STATE_INTR; \
19811636SXin.Chen@Sun.COM }
1995678Spl196000 #define AAC_STATUS_CLR(softs, mask) PCI_MEM_PUT32(softs, AAC_ODBR, mask)
2005678Spl196000 #define AAC_STATUS_GET(softs) PCI_MEM_GET32(softs, AAC_ODBR)
2015678Spl196000 #define AAC_NOTIFY(softs, val) PCI_MEM_PUT32(softs, AAC_IDBR, val)
2025678Spl196000 #define AAC_OUTB_GET(softs) PCI_MEM_GET32(softs, AAC_OQUE)
2035678Spl196000 #define AAC_OUTB_SET(softs, val) PCI_MEM_PUT32(softs, AAC_OQUE, val)
2045678Spl196000 #define AAC_FWSTATUS_GET(softs) \
2055678Spl196000 ((softs)->aac_if.aif_get_fwstatus(softs))
2065678Spl196000 #define AAC_MAILBOX_GET(softs, mb) \
2075678Spl196000 ((softs)->aac_if.aif_get_mailbox((softs), (mb)))
2085678Spl196000 #define AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3) \
2095678Spl196000 ((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
2105678Spl196000 (arg0), (arg1), (arg2), (arg3)))
2115678Spl196000
21211348SZhongyan.Gu@Sun.COM #define AAC_MGT_SLOT_NUM 2
2135678Spl196000 #define AAC_THROTTLE_DRAIN -1
2145678Spl196000
2155678Spl196000 #define AAC_QUIESCE_TICK 1 /* 1 second */
2167567SXin.Chen@Sun.COM #define AAC_QUIESCE_TIMEOUT 180 /* 180 seconds */
2175678Spl196000 #define AAC_DEFAULT_TICK 10 /* 10 seconds */
2185678Spl196000 #define AAC_SYNC_TICK (30*60) /* 30 minutes */
2195678Spl196000
2205678Spl196000 /* Poll time for aac_do_poll_io() */
2215678Spl196000 #define AAC_POLL_TIME 60 /* 60 seconds */
2225678Spl196000
2237567SXin.Chen@Sun.COM /* IOP reset */
2247567SXin.Chen@Sun.COM #define AAC_IOP_RESET_SUCCEED 0 /* IOP reset succeed */
2257567SXin.Chen@Sun.COM #define AAC_IOP_RESET_FAILED -1 /* IOP reset failed */
2267567SXin.Chen@Sun.COM #define AAC_IOP_RESET_ABNORMAL -2 /* Reset operation abnormal */
2277567SXin.Chen@Sun.COM
2285678Spl196000 /*
2295678Spl196000 * Hardware access functions
2305678Spl196000 */
2315678Spl196000 static int aac_rx_get_fwstatus(struct aac_softstate *);
2325678Spl196000 static int aac_rx_get_mailbox(struct aac_softstate *, int);
2335678Spl196000 static void aac_rx_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
2345678Spl196000 uint32_t, uint32_t, uint32_t);
2355678Spl196000 static int aac_rkt_get_fwstatus(struct aac_softstate *);
2365678Spl196000 static int aac_rkt_get_mailbox(struct aac_softstate *, int);
2375678Spl196000 static void aac_rkt_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
2385678Spl196000 uint32_t, uint32_t, uint32_t);
2395678Spl196000
2405678Spl196000 /*
2415678Spl196000 * SCSA function prototypes
2425678Spl196000 */
2435678Spl196000 static int aac_attach(dev_info_t *, ddi_attach_cmd_t);
2445678Spl196000 static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
2455678Spl196000 static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
2467656SSherry.Moore@Sun.COM static int aac_quiesce(dev_info_t *);
24711348SZhongyan.Gu@Sun.COM static int aac_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
2485678Spl196000
2495678Spl196000 /*
2505678Spl196000 * Interrupt handler functions
2515678Spl196000 */
2527000Sjd218194 static int aac_query_intrs(struct aac_softstate *, int);
2537000Sjd218194 static int aac_add_intrs(struct aac_softstate *);
2547000Sjd218194 static void aac_remove_intrs(struct aac_softstate *);
25511348SZhongyan.Gu@Sun.COM static int aac_enable_intrs(struct aac_softstate *);
25611348SZhongyan.Gu@Sun.COM static int aac_disable_intrs(struct aac_softstate *);
2575678Spl196000 static uint_t aac_intr_old(caddr_t);
2585678Spl196000 static uint_t aac_intr_new(caddr_t);
2595678Spl196000 static uint_t aac_softintr(caddr_t);
2605678Spl196000
2615678Spl196000 /*
2625678Spl196000 * Internal functions in attach
2635678Spl196000 */
2645678Spl196000 static int aac_check_card_type(struct aac_softstate *);
2655678Spl196000 static int aac_check_firmware(struct aac_softstate *);
2665678Spl196000 static int aac_common_attach(struct aac_softstate *);
2675678Spl196000 static void aac_common_detach(struct aac_softstate *);
2685678Spl196000 static int aac_probe_containers(struct aac_softstate *);
2695678Spl196000 static int aac_alloc_comm_space(struct aac_softstate *);
2705678Spl196000 static int aac_setup_comm_space(struct aac_softstate *);
2715678Spl196000 static void aac_free_comm_space(struct aac_softstate *);
2725678Spl196000 static int aac_hba_setup(struct aac_softstate *);
2735678Spl196000
2745678Spl196000 /*
2755678Spl196000 * Sync FIB operation functions
2765678Spl196000 */
2775678Spl196000 int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
2785678Spl196000 uint32_t, uint32_t, uint32_t, uint32_t *);
2795678Spl196000 static int aac_sync_fib(struct aac_softstate *, uint16_t, uint16_t);
2805678Spl196000
2815678Spl196000 /*
2825678Spl196000 * Command queue operation functions
2835678Spl196000 */
2845678Spl196000 static void aac_cmd_initq(struct aac_cmd_queue *);
2855678Spl196000 static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
2865678Spl196000 static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
2875678Spl196000 static void aac_cmd_delete(struct aac_cmd_queue *, struct aac_cmd *);
2885678Spl196000
2895678Spl196000 /*
2905678Spl196000 * FIB queue operation functions
2915678Spl196000 */
2925678Spl196000 static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
2935678Spl196000 static int aac_fib_dequeue(struct aac_softstate *, int, int *);
2945678Spl196000
2955678Spl196000 /*
2965678Spl196000 * Slot operation functions
2975678Spl196000 */
2985678Spl196000 static int aac_create_slots(struct aac_softstate *);
2995678Spl196000 static void aac_destroy_slots(struct aac_softstate *);
3005678Spl196000 static void aac_alloc_fibs(struct aac_softstate *);
3015678Spl196000 static void aac_destroy_fibs(struct aac_softstate *);
3025678Spl196000 static struct aac_slot *aac_get_slot(struct aac_softstate *);
3035678Spl196000 static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
3045678Spl196000 static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
3055678Spl196000 static void aac_free_fib(struct aac_slot *);
3065678Spl196000
3075678Spl196000 /*
3085678Spl196000 * Internal functions
3095678Spl196000 */
31011348SZhongyan.Gu@Sun.COM static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *,
31111348SZhongyan.Gu@Sun.COM uint16_t);
3125678Spl196000 static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *);
3135678Spl196000 static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *);
3145678Spl196000 static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *);
3155678Spl196000 static void aac_cmd_fib_sync(struct aac_softstate *, struct aac_cmd *);
3165678Spl196000 static void aac_cmd_fib_scsi32(struct aac_softstate *, struct aac_cmd *);
3175678Spl196000 static void aac_cmd_fib_scsi64(struct aac_softstate *, struct aac_cmd *);
31810976SZhongyan.Gu@Sun.COM static void aac_cmd_fib_startstop(struct aac_softstate *, struct aac_cmd *);
3195678Spl196000 static void aac_start_waiting_io(struct aac_softstate *);
3205678Spl196000 static void aac_drain_comp_q(struct aac_softstate *);
3215678Spl196000 int aac_do_io(struct aac_softstate *, struct aac_cmd *);
32211348SZhongyan.Gu@Sun.COM static int aac_sync_fib_slot_bind(struct aac_softstate *, struct aac_cmd *);
32311348SZhongyan.Gu@Sun.COM static void aac_sync_fib_slot_release(struct aac_softstate *, struct aac_cmd *);
32411348SZhongyan.Gu@Sun.COM static void aac_start_io(struct aac_softstate *, struct aac_cmd *);
3255678Spl196000 static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
3265678Spl196000 static int aac_do_sync_io(struct aac_softstate *, struct aac_cmd *);
3275678Spl196000 static int aac_send_command(struct aac_softstate *, struct aac_slot *);
3287567SXin.Chen@Sun.COM static void aac_cmd_timeout(struct aac_softstate *, struct aac_cmd *);
3295678Spl196000 static int aac_dma_sync_ac(struct aac_cmd *);
3305678Spl196000 static int aac_shutdown(struct aac_softstate *);
3315678Spl196000 static int aac_reset_adapter(struct aac_softstate *);
3325678Spl196000 static int aac_do_quiesce(struct aac_softstate *softs);
3335678Spl196000 static int aac_do_unquiesce(struct aac_softstate *softs);
3345678Spl196000 static void aac_unhold_bus(struct aac_softstate *, int);
3357567SXin.Chen@Sun.COM static void aac_set_throttle(struct aac_softstate *, struct aac_device *,
3365678Spl196000 int, int);
3375678Spl196000
3385678Spl196000 /*
3395678Spl196000 * Adapter Initiated FIB handling function
3405678Spl196000 */
34111964SXin.Chen@Sun.COM static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
34211964SXin.Chen@Sun.COM struct aac_fib *, int);
34311964SXin.Chen@Sun.COM static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
3445678Spl196000
3455678Spl196000 /*
34611964SXin.Chen@Sun.COM * Event handling related functions
3475678Spl196000 */
34811964SXin.Chen@Sun.COM static void aac_timer(void *);
34911964SXin.Chen@Sun.COM static void aac_event_thread(struct aac_softstate *);
35011964SXin.Chen@Sun.COM static void aac_event_disp(struct aac_softstate *, int);
3515678Spl196000
3525678Spl196000 /*
3535678Spl196000 * IOCTL interface related functions
3545678Spl196000 */
3555678Spl196000 static int aac_open(dev_t *, int, int, cred_t *);
3565678Spl196000 static int aac_close(dev_t, int, int, cred_t *);
3575678Spl196000 static int aac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
3585678Spl196000 extern int aac_do_ioctl(struct aac_softstate *, dev_t, int, intptr_t, int);
3595678Spl196000
3605678Spl196000 /*
3615678Spl196000 * FMA Prototypes
3625678Spl196000 */
3635678Spl196000 static void aac_fm_init(struct aac_softstate *);
3645678Spl196000 static void aac_fm_fini(struct aac_softstate *);
3655678Spl196000 static int aac_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
3665678Spl196000 int aac_check_acc_handle(ddi_acc_handle_t);
3675678Spl196000 int aac_check_dma_handle(ddi_dma_handle_t);
3685678Spl196000 void aac_fm_ereport(struct aac_softstate *, char *);
3695678Spl196000
3707567SXin.Chen@Sun.COM /*
3717567SXin.Chen@Sun.COM * Auto enumeration functions
3727567SXin.Chen@Sun.COM */
3737567SXin.Chen@Sun.COM static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
3747567SXin.Chen@Sun.COM static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
3757567SXin.Chen@Sun.COM void *, dev_info_t **);
37611964SXin.Chen@Sun.COM static int aac_handle_dr(struct aac_softstate *, int, int, int);
37711964SXin.Chen@Sun.COM
37811964SXin.Chen@Sun.COM extern pri_t minclsyspri;
3797567SXin.Chen@Sun.COM
3805678Spl196000 #ifdef DEBUG
3815678Spl196000 /*
3825678Spl196000 * UART debug output support
3835678Spl196000 */
3845678Spl196000
3855678Spl196000 #define AAC_PRINT_BUFFER_SIZE 512
3865678Spl196000 #define AAC_PRINT_TIMEOUT 250 /* 1/4 sec. = 250 msec. */
3875678Spl196000
3885678Spl196000 #define AAC_FW_DBG_STRLEN_OFFSET 0x00
3895678Spl196000 #define AAC_FW_DBG_FLAGS_OFFSET 0x04
3905678Spl196000 #define AAC_FW_DBG_BLED_OFFSET 0x08
3915678Spl196000
3925678Spl196000 static int aac_get_fw_debug_buffer(struct aac_softstate *);
3935678Spl196000 static void aac_print_scmd(struct aac_softstate *, struct aac_cmd *);
3945678Spl196000 static void aac_print_aif(struct aac_softstate *, struct aac_aif_command *);
3955678Spl196000
3965678Spl196000 static char aac_prt_buf[AAC_PRINT_BUFFER_SIZE];
3975678Spl196000 static char aac_fmt[] = " %s";
3985678Spl196000 static char aac_fmt_header[] = " %s.%d: %s";
3995678Spl196000 static kmutex_t aac_prt_mutex;
4005678Spl196000
4015678Spl196000 /*
4025678Spl196000 * Debug flags to be put into the softstate flags field
4035678Spl196000 * when initialized
4045678Spl196000 */
4055678Spl196000 uint32_t aac_debug_flags =
4065678Spl196000 /* AACDB_FLAGS_KERNEL_PRINT | */
4075678Spl196000 /* AACDB_FLAGS_FW_PRINT | */
4085678Spl196000 /* AACDB_FLAGS_MISC | */
4095678Spl196000 /* AACDB_FLAGS_FUNC1 | */
4105678Spl196000 /* AACDB_FLAGS_FUNC2 | */
4115678Spl196000 /* AACDB_FLAGS_SCMD | */
4125678Spl196000 /* AACDB_FLAGS_AIF | */
4135678Spl196000 /* AACDB_FLAGS_FIB | */
4145678Spl196000 /* AACDB_FLAGS_IOCTL | */
4155678Spl196000 0;
4167567SXin.Chen@Sun.COM uint32_t aac_debug_fib_flags =
4177567SXin.Chen@Sun.COM /* AACDB_FLAGS_FIB_RW | */
4187567SXin.Chen@Sun.COM /* AACDB_FLAGS_FIB_IOCTL | */
4197567SXin.Chen@Sun.COM /* AACDB_FLAGS_FIB_SRB | */
4207567SXin.Chen@Sun.COM /* AACDB_FLAGS_FIB_SYNC | */
4217567SXin.Chen@Sun.COM /* AACDB_FLAGS_FIB_HEADER | */
4227567SXin.Chen@Sun.COM /* AACDB_FLAGS_FIB_TIMEOUT | */
4237567SXin.Chen@Sun.COM 0;
4245678Spl196000
4255678Spl196000 #endif /* DEBUG */
4265678Spl196000
4275678Spl196000 static struct cb_ops aac_cb_ops = {
4285678Spl196000 aac_open, /* open */
4295678Spl196000 aac_close, /* close */
4305678Spl196000 nodev, /* strategy */
4315678Spl196000 nodev, /* print */
4325678Spl196000 nodev, /* dump */
4335678Spl196000 nodev, /* read */
4345678Spl196000 nodev, /* write */
4355678Spl196000 aac_ioctl, /* ioctl */
4365678Spl196000 nodev, /* devmap */
4375678Spl196000 nodev, /* mmap */
4385678Spl196000 nodev, /* segmap */
4395678Spl196000 nochpoll, /* poll */
4405678Spl196000 ddi_prop_op, /* cb_prop_op */
4415678Spl196000 NULL, /* streamtab */
4425678Spl196000 D_64BIT | D_NEW | D_MP | D_HOTPLUG, /* cb_flag */
4435678Spl196000 CB_REV, /* cb_rev */
4445678Spl196000 nodev, /* async I/O read entry point */
4455678Spl196000 nodev /* async I/O write entry point */
4465678Spl196000 };
4475678Spl196000
4485678Spl196000 static struct dev_ops aac_dev_ops = {
4495678Spl196000 DEVO_REV,
4505678Spl196000 0,
45111348SZhongyan.Gu@Sun.COM aac_getinfo,
4525678Spl196000 nulldev,
4535678Spl196000 nulldev,
4545678Spl196000 aac_attach,
4555678Spl196000 aac_detach,
4565678Spl196000 aac_reset,
4575678Spl196000 &aac_cb_ops,
4585678Spl196000 NULL,
4597656SSherry.Moore@Sun.COM NULL,
4607656SSherry.Moore@Sun.COM aac_quiesce,
4615678Spl196000 };
4625678Spl196000
4635678Spl196000 static struct modldrv aac_modldrv = {
4645678Spl196000 &mod_driverops,
4655678Spl196000 "AAC Driver " AAC_DRIVER_VERSION,
4665678Spl196000 &aac_dev_ops,
4675678Spl196000 };
4685678Spl196000
4695678Spl196000 static struct modlinkage aac_modlinkage = {
4705678Spl196000 MODREV_1,
4715678Spl196000 &aac_modldrv,
4725678Spl196000 NULL
4735678Spl196000 };
4745678Spl196000
4755678Spl196000 static struct aac_softstate *aac_softstatep;
4765678Spl196000
4775678Spl196000 /*
4785678Spl196000 * Supported card list
4795678Spl196000 * ordered in vendor id, subvendor id, subdevice id, and device id
4805678Spl196000 */
4815678Spl196000 static struct aac_card_type aac_cards[] = {
4825678Spl196000 {0x1028, 0x1, 0x1028, 0x1, AAC_HWIF_I960RX,
4835678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4845678Spl196000 "Dell", "PERC 3/Di"},
4855678Spl196000 {0x1028, 0x2, 0x1028, 0x2, AAC_HWIF_I960RX,
4865678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4875678Spl196000 "Dell", "PERC 3/Di"},
4885678Spl196000 {0x1028, 0x3, 0x1028, 0x3, AAC_HWIF_I960RX,
4895678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4905678Spl196000 "Dell", "PERC 3/Si"},
4915678Spl196000 {0x1028, 0x8, 0x1028, 0xcf, AAC_HWIF_I960RX,
4925678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4935678Spl196000 "Dell", "PERC 3/Di"},
4945678Spl196000 {0x1028, 0x4, 0x1028, 0xd0, AAC_HWIF_I960RX,
4955678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4965678Spl196000 "Dell", "PERC 3/Si"},
4975678Spl196000 {0x1028, 0x2, 0x1028, 0xd1, AAC_HWIF_I960RX,
4985678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4995678Spl196000 "Dell", "PERC 3/Di"},
5005678Spl196000 {0x1028, 0x2, 0x1028, 0xd9, AAC_HWIF_I960RX,
5015678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5025678Spl196000 "Dell", "PERC 3/Di"},
5035678Spl196000 {0x1028, 0xa, 0x1028, 0x106, AAC_HWIF_I960RX,
5045678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5055678Spl196000 "Dell", "PERC 3/Di"},
5065678Spl196000 {0x1028, 0xa, 0x1028, 0x11b, AAC_HWIF_I960RX,
5075678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5085678Spl196000 "Dell", "PERC 3/Di"},
5095678Spl196000 {0x1028, 0xa, 0x1028, 0x121, AAC_HWIF_I960RX,
5105678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5115678Spl196000 "Dell", "PERC 3/Di"},
5125678Spl196000 {0x9005, 0x285, 0x1028, 0x287, AAC_HWIF_I960RX,
5135678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5145678Spl196000 "Dell", "PERC 320/DC"},
5155678Spl196000 {0x9005, 0x285, 0x1028, 0x291, AAC_HWIF_I960RX,
5165678Spl196000 AAC_FLAGS_17SG, AAC_TYPE_SATA, "Dell", "CERC SR2"},
5175678Spl196000
5185678Spl196000 {0x9005, 0x285, 0x1014, 0x2f2, AAC_HWIF_I960RX,
5195678Spl196000 0, AAC_TYPE_SCSI, "IBM", "ServeRAID 8i"},
5205678Spl196000 {0x9005, 0x285, 0x1014, 0x34d, AAC_HWIF_I960RX,
5215678Spl196000 0, AAC_TYPE_SAS, "IBM", "ServeRAID 8s"},
5225678Spl196000 {0x9005, 0x286, 0x1014, 0x9580, AAC_HWIF_RKT,
5235678Spl196000 0, AAC_TYPE_SAS, "IBM", "ServeRAID 8k"},
5245678Spl196000
5255678Spl196000 {0x9005, 0x285, 0x103c, 0x3227, AAC_HWIF_I960RX,
5265678Spl196000 AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
5275678Spl196000 {0x9005, 0x285, 0xe11, 0x295, AAC_HWIF_I960RX,
5285678Spl196000 AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
5295678Spl196000
5305678Spl196000 {0x9005, 0x285, 0x9005, 0x285, AAC_HWIF_I960RX,
5315678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5325678Spl196000 "Adaptec", "2200S"},
5335678Spl196000 {0x9005, 0x285, 0x9005, 0x286, AAC_HWIF_I960RX,
5345678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5355678Spl196000 "Adaptec", "2120S"},
5365678Spl196000 {0x9005, 0x285, 0x9005, 0x287, AAC_HWIF_I960RX,
5375678Spl196000 AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5385678Spl196000 "Adaptec", "2200S"},
5395678Spl196000 {0x9005, 0x285, 0x9005, 0x288, AAC_HWIF_I960RX,
5405678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "3230S"},
5415678Spl196000 {0x9005, 0x285, 0x9005, 0x289, AAC_HWIF_I960RX,
5425678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "3240S"},
5435678Spl196000 {0x9005, 0x285, 0x9005, 0x28a, AAC_HWIF_I960RX,
5445678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "2020ZCR"},
5455678Spl196000 {0x9005, 0x285, 0x9005, 0x28b, AAC_HWIF_I960RX,
5465678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "2025ZCR"},
5475678Spl196000 {0x9005, 0x286, 0x9005, 0x28c, AAC_HWIF_RKT,
5485678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "2230S"},
5495678Spl196000 {0x9005, 0x286, 0x9005, 0x28d, AAC_HWIF_RKT,
5505678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "2130S"},
5515678Spl196000 {0x9005, 0x285, 0x9005, 0x28e, AAC_HWIF_I960RX,
5525678Spl196000 0, AAC_TYPE_SATA, "Adaptec", "2020SA"},
5535678Spl196000 {0x9005, 0x285, 0x9005, 0x28f, AAC_HWIF_I960RX,
5545678Spl196000 0, AAC_TYPE_SATA, "Adaptec", "2025SA"},
5555678Spl196000 {0x9005, 0x285, 0x9005, 0x290, AAC_HWIF_I960RX,
5565678Spl196000 AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2410SA"},
5575678Spl196000 {0x9005, 0x285, 0x9005, 0x292, AAC_HWIF_I960RX,
5585678Spl196000 AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2810SA"},
5595678Spl196000 {0x9005, 0x285, 0x9005, 0x293, AAC_HWIF_I960RX,
5605678Spl196000 AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "21610SA"},
5615678Spl196000 {0x9005, 0x285, 0x9005, 0x294, AAC_HWIF_I960RX,
5625678Spl196000 0, AAC_TYPE_SATA, "Adaptec", "2026ZCR"},
5635678Spl196000 {0x9005, 0x285, 0x9005, 0x296, AAC_HWIF_I960RX,
5645678Spl196000 0, AAC_TYPE_SCSI, "Adaptec", "2240S"},
5655678Spl196000 {0x9005, 0x285, 0x9005, 0x297, AAC_HWIF_I960RX,
5665678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "4005SAS"},
5675678Spl196000 {0x9005, 0x285, 0x9005, 0x298, AAC_HWIF_I960RX,
5685678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "RAID 4000"},
5695678Spl196000 {0x9005, 0x285, 0x9005, 0x299, AAC_HWIF_I960RX,
5705678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "4800SAS"},
5715678Spl196000 {0x9005, 0x285, 0x9005, 0x29a, AAC_HWIF_I960RX,
5725678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "4805SAS"},
5735678Spl196000 {0x9005, 0x286, 0x9005, 0x29b, AAC_HWIF_RKT,
5745678Spl196000 0, AAC_TYPE_SATA, "Adaptec", "2820SA"},
5755678Spl196000 {0x9005, 0x286, 0x9005, 0x29c, AAC_HWIF_RKT,
5765678Spl196000 0, AAC_TYPE_SATA, "Adaptec", "2620SA"},
5775678Spl196000 {0x9005, 0x286, 0x9005, 0x29d, AAC_HWIF_RKT,
5785678Spl196000 0, AAC_TYPE_SATA, "Adaptec", "2420SA"},
5795678Spl196000 {0x9005, 0x286, 0x9005, 0x29e, AAC_HWIF_RKT,
5805678Spl196000 0, AAC_TYPE_SATA, "ICP", "9024RO"},
5815678Spl196000 {0x9005, 0x286, 0x9005, 0x29f, AAC_HWIF_RKT,
5825678Spl196000 0, AAC_TYPE_SATA, "ICP", "9014RO"},
5835678Spl196000 {0x9005, 0x286, 0x9005, 0x2a0, AAC_HWIF_RKT,
5845678Spl196000 0, AAC_TYPE_SATA, "ICP", "9047MA"},
5855678Spl196000 {0x9005, 0x286, 0x9005, 0x2a1, AAC_HWIF_RKT,
5865678Spl196000 0, AAC_TYPE_SATA, "ICP", "9087MA"},
5875678Spl196000 {0x9005, 0x285, 0x9005, 0x2a4, AAC_HWIF_I960RX,
5885678Spl196000 0, AAC_TYPE_SAS, "ICP", "9085LI"},
5895678Spl196000 {0x9005, 0x285, 0x9005, 0x2a5, AAC_HWIF_I960RX,
5905678Spl196000 0, AAC_TYPE_SAS, "ICP", "5085BR"},
5915678Spl196000 {0x9005, 0x286, 0x9005, 0x2a6, AAC_HWIF_RKT,
5925678Spl196000 0, AAC_TYPE_SATA, "ICP", "9067MA"},
5935678Spl196000 {0x9005, 0x285, 0x9005, 0x2b5, AAC_HWIF_I960RX,
5945678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "RAID 5445"},
5955678Spl196000 {0x9005, 0x285, 0x9005, 0x2b6, AAC_HWIF_I960RX,
5965678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "RAID 5805"},
5975678Spl196000 {0x9005, 0x285, 0x9005, 0x2b7, AAC_HWIF_I960RX,
5985678Spl196000 0, AAC_TYPE_SAS, "Adaptec", "RAID 5085"},
5995678Spl196000 {0x9005, 0x285, 0x9005, 0x2b8, AAC_HWIF_I960RX,
6005678Spl196000 0, AAC_TYPE_SAS, "ICP", "RAID ICP5445SL"},
6015678Spl196000 {0x9005, 0x285, 0x9005, 0x2b9, AAC_HWIF_I960RX,
6025678Spl196000 0, AAC_TYPE_SAS, "ICP", "RAID ICP5085SL"},
6035678Spl196000 {0x9005, 0x285, 0x9005, 0x2ba, AAC_HWIF_I960RX,
6045678Spl196000 0, AAC_TYPE_SAS, "ICP", "RAID ICP5805SL"},
6055678Spl196000
6065678Spl196000 {0, 0, 0, 0, AAC_HWIF_UNKNOWN,
6075678Spl196000 0, AAC_TYPE_UNKNOWN, "Unknown", "AAC card"},
6085678Spl196000 };
6095678Spl196000
6105678Spl196000 /*
6115678Spl196000 * Hardware access functions for i960 based cards
6125678Spl196000 */
6135678Spl196000 static struct aac_interface aac_rx_interface = {
6145678Spl196000 aac_rx_get_fwstatus,
6155678Spl196000 aac_rx_get_mailbox,
6165678Spl196000 aac_rx_set_mailbox
6175678Spl196000 };
6185678Spl196000
6195678Spl196000 /*
6205678Spl196000 * Hardware access functions for Rocket based cards
6215678Spl196000 */
6225678Spl196000 static struct aac_interface aac_rkt_interface = {
6235678Spl196000 aac_rkt_get_fwstatus,
6245678Spl196000 aac_rkt_get_mailbox,
6255678Spl196000 aac_rkt_set_mailbox
6265678Spl196000 };
6275678Spl196000
6285678Spl196000 ddi_device_acc_attr_t aac_acc_attr = {
62911236SStephen.Hanson@Sun.COM DDI_DEVICE_ATTR_V1,
6305678Spl196000 DDI_STRUCTURE_LE_ACC,
63111236SStephen.Hanson@Sun.COM DDI_STRICTORDER_ACC,
63211236SStephen.Hanson@Sun.COM DDI_DEFAULT_ACC
6335678Spl196000 };
6345678Spl196000
6355678Spl196000 static struct {
6365678Spl196000 int size;
6375678Spl196000 int notify;
6385678Spl196000 } aac_qinfo[] = {
6395678Spl196000 {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
6405678Spl196000 {AAC_HOST_HIGH_CMD_ENTRIES, 0},
6415678Spl196000 {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
6425678Spl196000 {AAC_ADAP_HIGH_CMD_ENTRIES, 0},
6435678Spl196000 {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
6445678Spl196000 {AAC_HOST_HIGH_RESP_ENTRIES, 0},
6455678Spl196000 {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
6465678Spl196000 {AAC_ADAP_HIGH_RESP_ENTRIES, 0}
6475678Spl196000 };
6485678Spl196000
6495678Spl196000 /*
6505678Spl196000 * Default aac dma attributes
6515678Spl196000 */
6525678Spl196000 static ddi_dma_attr_t aac_dma_attr = {
6535678Spl196000 DMA_ATTR_V0,
6545678Spl196000 0, /* lowest usable address */
6555678Spl196000 0xffffffffull, /* high DMA address range */
6565678Spl196000 0xffffffffull, /* DMA counter register */
6575678Spl196000 AAC_DMA_ALIGN, /* DMA address alignment */
6585678Spl196000 1, /* DMA burstsizes */
6595678Spl196000 1, /* min effective DMA size */
6605678Spl196000 0xffffffffull, /* max DMA xfer size */
6615678Spl196000 0xffffffffull, /* segment boundary */
6625678Spl196000 1, /* s/g list length */
6635678Spl196000 AAC_BLK_SIZE, /* granularity of device */
6647567SXin.Chen@Sun.COM 0 /* DMA transfer flags */
6657567SXin.Chen@Sun.COM };
6667567SXin.Chen@Sun.COM
6675678Spl196000 static int aac_tick = AAC_DEFAULT_TICK; /* tick for the internal timer */
6685678Spl196000 static uint32_t aac_timebase = 0; /* internal timer in seconds */
6695678Spl196000
6705678Spl196000 /*
6715678Spl196000 * Warlock directives
6725678Spl196000 *
6735678Spl196000 * Different variables with the same types have to be protected by the
6745678Spl196000 * same mutex; otherwise, warlock will complain with "variables don't
6755678Spl196000 * seem to be protected consistently". For example,
6765678Spl196000 * aac_softstate::{q_wait, q_comp} are type of aac_cmd_queue, and protected
6775678Spl196000 * by aac_softstate::{io_lock, q_comp_mutex} respectively. We have to
6785678Spl196000 * declare them as protected explictly at aac_cmd_dequeue().
6795678Spl196000 */
6805678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt scsi_cdb scsi_status \
6815678Spl196000 scsi_arq_status scsi_descr_sense_hdr scsi_information_sense_descr \
6825678Spl196000 mode_format mode_geometry mode_header aac_cmd))
6835678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_cmd", aac_fib ddi_dma_cookie_t \
6845678Spl196000 aac_sge))
6855678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_fib", aac_blockread aac_blockwrite \
6865678Spl196000 aac_blockread64 aac_raw_io aac_sg_entry aac_sg_entry64 aac_sg_entryraw \
6875678Spl196000 aac_sg_table aac_srb))
6885678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
6895678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
6907567SXin.Chen@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
6915678Spl196000
6925678Spl196000 int
_init(void)6935678Spl196000 _init(void)
6945678Spl196000 {
6955678Spl196000 int rval = 0;
6965678Spl196000
6975678Spl196000 #ifdef DEBUG
6985678Spl196000 mutex_init(&aac_prt_mutex, NULL, MUTEX_DRIVER, NULL);
6995678Spl196000 #endif
7005678Spl196000 DBCALLED(NULL, 1);
7015678Spl196000
7025678Spl196000 if ((rval = ddi_soft_state_init((void *)&aac_softstatep,
7035678Spl196000 sizeof (struct aac_softstate), 0)) != 0)
7045678Spl196000 goto error;
7055678Spl196000
7065678Spl196000 if ((rval = scsi_hba_init(&aac_modlinkage)) != 0) {
7075678Spl196000 ddi_soft_state_fini((void *)&aac_softstatep);
7085678Spl196000 goto error;
7095678Spl196000 }
7105678Spl196000
7115678Spl196000 if ((rval = mod_install(&aac_modlinkage)) != 0) {
7125678Spl196000 ddi_soft_state_fini((void *)&aac_softstatep);
7135678Spl196000 scsi_hba_fini(&aac_modlinkage);
7145678Spl196000 goto error;
7155678Spl196000 }
7165678Spl196000 return (rval);
7175678Spl196000
7185678Spl196000 error:
7195678Spl196000 AACDB_PRINT(NULL, CE_WARN, "Mod init error!");
7205678Spl196000 #ifdef DEBUG
7215678Spl196000 mutex_destroy(&aac_prt_mutex);
7225678Spl196000 #endif
7235678Spl196000 return (rval);
7245678Spl196000 }
7255678Spl196000
7265678Spl196000 int
_info(struct modinfo * modinfop)7275678Spl196000 _info(struct modinfo *modinfop)
7285678Spl196000 {
7295678Spl196000 DBCALLED(NULL, 1);
7305678Spl196000 return (mod_info(&aac_modlinkage, modinfop));
7315678Spl196000 }
7325678Spl196000
7335678Spl196000 /*
7345678Spl196000 * An HBA driver cannot be unload unless you reboot,
7355678Spl196000 * so this function will be of no use.
7365678Spl196000 */
7375678Spl196000 int
_fini(void)7385678Spl196000 _fini(void)
7395678Spl196000 {
7405678Spl196000 int rval;
7415678Spl196000
7425678Spl196000 DBCALLED(NULL, 1);
7435678Spl196000
7445678Spl196000 if ((rval = mod_remove(&aac_modlinkage)) != 0)
7455678Spl196000 goto error;
7465678Spl196000
7475678Spl196000 scsi_hba_fini(&aac_modlinkage);
7485678Spl196000 ddi_soft_state_fini((void *)&aac_softstatep);
7495678Spl196000 #ifdef DEBUG
7505678Spl196000 mutex_destroy(&aac_prt_mutex);
7515678Spl196000 #endif
7525678Spl196000 return (0);
7535678Spl196000
7545678Spl196000 error:
7555678Spl196000 AACDB_PRINT(NULL, CE_WARN, "AAC is busy, cannot unload!");
7565678Spl196000 return (rval);
7575678Spl196000 }
7585678Spl196000
7595678Spl196000 static int
aac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)7605678Spl196000 aac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7615678Spl196000 {
7625678Spl196000 int instance, i;
7635678Spl196000 struct aac_softstate *softs = NULL;
7645678Spl196000 int attach_state = 0;
7657567SXin.Chen@Sun.COM char *data;
7665678Spl196000
7675678Spl196000 DBCALLED(NULL, 1);
7685678Spl196000
7695678Spl196000 switch (cmd) {
7705678Spl196000 case DDI_ATTACH:
7715678Spl196000 break;
7725678Spl196000 case DDI_RESUME:
7735678Spl196000 return (DDI_FAILURE);
7745678Spl196000 default:
7755678Spl196000 return (DDI_FAILURE);
7765678Spl196000 }
7775678Spl196000
7785678Spl196000 instance = ddi_get_instance(dip);
7795678Spl196000
7805678Spl196000 /* Get soft state */
7815678Spl196000 if (ddi_soft_state_zalloc(aac_softstatep, instance) != DDI_SUCCESS) {
7825678Spl196000 AACDB_PRINT(softs, CE_WARN, "Cannot alloc soft state");
7835678Spl196000 goto error;
7845678Spl196000 }
7855678Spl196000 softs = ddi_get_soft_state(aac_softstatep, instance);
7865678Spl196000 attach_state |= AAC_ATTACH_SOFTSTATE_ALLOCED;
7875678Spl196000
7885678Spl196000 softs->instance = instance;
7895678Spl196000 softs->devinfo_p = dip;
7905678Spl196000 softs->buf_dma_attr = softs->addr_dma_attr = aac_dma_attr;
7915678Spl196000 softs->addr_dma_attr.dma_attr_granular = 1;
7927567SXin.Chen@Sun.COM softs->acc_attr = aac_acc_attr;
79311236SStephen.Hanson@Sun.COM softs->reg_attr = aac_acc_attr;
7945678Spl196000 softs->card = AAC_UNKNOWN_CARD;
7955678Spl196000 #ifdef DEBUG
7965678Spl196000 softs->debug_flags = aac_debug_flags;
7977567SXin.Chen@Sun.COM softs->debug_fib_flags = aac_debug_fib_flags;
7985678Spl196000 #endif
7995678Spl196000
8007567SXin.Chen@Sun.COM /* Initialize FMA */
8017567SXin.Chen@Sun.COM aac_fm_init(softs);
8027567SXin.Chen@Sun.COM
8035678Spl196000 /* Check the card type */
8045678Spl196000 if (aac_check_card_type(softs) == AACERR) {
8055678Spl196000 AACDB_PRINT(softs, CE_WARN, "Card not supported");
8065678Spl196000 goto error;
8075678Spl196000 }
8085678Spl196000 /* We have found the right card and everything is OK */
8095678Spl196000 attach_state |= AAC_ATTACH_CARD_DETECTED;
8105678Spl196000
8115678Spl196000 /* Map PCI mem space */
8125678Spl196000 if (ddi_regs_map_setup(dip, 1,
8135678Spl196000 (caddr_t *)&softs->pci_mem_base_vaddr, 0,
81411236SStephen.Hanson@Sun.COM softs->map_size_min, &softs->reg_attr,
8155678Spl196000 &softs->pci_mem_handle) != DDI_SUCCESS)
8165678Spl196000 goto error;
8175678Spl196000
8185678Spl196000 softs->map_size = softs->map_size_min;
8195678Spl196000 attach_state |= AAC_ATTACH_PCI_MEM_MAPPED;
8205678Spl196000
8215678Spl196000 AAC_DISABLE_INTR(softs);
8225678Spl196000
82311348SZhongyan.Gu@Sun.COM /* Init mutexes and condvars */
82411964SXin.Chen@Sun.COM mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
82511964SXin.Chen@Sun.COM DDI_INTR_PRI(softs->intr_pri));
82611964SXin.Chen@Sun.COM mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
82711964SXin.Chen@Sun.COM DDI_INTR_PRI(softs->intr_pri));
82811964SXin.Chen@Sun.COM mutex_init(&softs->time_mutex, NULL, MUTEX_DRIVER,
82911964SXin.Chen@Sun.COM DDI_INTR_PRI(softs->intr_pri));
83011964SXin.Chen@Sun.COM mutex_init(&softs->ev_lock, NULL, MUTEX_DRIVER,
83111964SXin.Chen@Sun.COM DDI_INTR_PRI(softs->intr_pri));
83211964SXin.Chen@Sun.COM mutex_init(&softs->aifq_mutex, NULL,
8337000Sjd218194 MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
8345678Spl196000 cv_init(&softs->event, NULL, CV_DRIVER, NULL);
83511636SXin.Chen@Sun.COM cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
8365678Spl196000 cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
83711964SXin.Chen@Sun.COM cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
83811964SXin.Chen@Sun.COM cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
83911964SXin.Chen@Sun.COM cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
8405678Spl196000 attach_state |= AAC_ATTACH_KMUTEX_INITED;
8415678Spl196000
84211348SZhongyan.Gu@Sun.COM /* Init the cmd queues */
84311348SZhongyan.Gu@Sun.COM for (i = 0; i < AAC_CMDQ_NUM; i++)
84411348SZhongyan.Gu@Sun.COM aac_cmd_initq(&softs->q_wait[i]);
84511348SZhongyan.Gu@Sun.COM aac_cmd_initq(&softs->q_busy);
84611348SZhongyan.Gu@Sun.COM aac_cmd_initq(&softs->q_comp);
84711348SZhongyan.Gu@Sun.COM
8487567SXin.Chen@Sun.COM /* Check for legacy device naming support */
8497567SXin.Chen@Sun.COM softs->legacy = 1; /* default to use legacy name */
8507567SXin.Chen@Sun.COM if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
8517567SXin.Chen@Sun.COM "legacy-name-enable", &data) == DDI_SUCCESS)) {
8527567SXin.Chen@Sun.COM if (strcmp(data, "no") == 0) {
8537567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "legacy-name disabled");
8547567SXin.Chen@Sun.COM softs->legacy = 0;
8557567SXin.Chen@Sun.COM }
8567567SXin.Chen@Sun.COM ddi_prop_free(data);
8577567SXin.Chen@Sun.COM }
8587567SXin.Chen@Sun.COM
8595678Spl196000 /*
8605678Spl196000 * Everything has been set up till now,
8615678Spl196000 * we will do some common attach.
8625678Spl196000 */
86311348SZhongyan.Gu@Sun.COM mutex_enter(&softs->io_lock);
86411348SZhongyan.Gu@Sun.COM if (aac_common_attach(softs) == AACERR) {
86511348SZhongyan.Gu@Sun.COM mutex_exit(&softs->io_lock);
8665678Spl196000 goto error;
86711348SZhongyan.Gu@Sun.COM }
86811348SZhongyan.Gu@Sun.COM mutex_exit(&softs->io_lock);
8695678Spl196000 attach_state |= AAC_ATTACH_COMM_SPACE_SETUP;
8705678Spl196000
8718551SPeng.L@Sun.COM /* Check for buf breakup support */
8728551SPeng.L@Sun.COM if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
8738551SPeng.L@Sun.COM "breakup-enable", &data) == DDI_SUCCESS)) {
8748551SPeng.L@Sun.COM if (strcmp(data, "yes") == 0) {
8758551SPeng.L@Sun.COM AACDB_PRINT(softs, CE_NOTE, "buf breakup enabled");
8768551SPeng.L@Sun.COM softs->flags |= AAC_FLAGS_BRKUP;
8778551SPeng.L@Sun.COM }
8788551SPeng.L@Sun.COM ddi_prop_free(data);
8798551SPeng.L@Sun.COM }
8808551SPeng.L@Sun.COM softs->dma_max = softs->buf_dma_attr.dma_attr_maxxfer;
8818551SPeng.L@Sun.COM if (softs->flags & AAC_FLAGS_BRKUP) {
8828551SPeng.L@Sun.COM softs->dma_max = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
8838551SPeng.L@Sun.COM DDI_PROP_DONTPASS, "dma-max", softs->dma_max);
8848551SPeng.L@Sun.COM }
8858551SPeng.L@Sun.COM
8865678Spl196000 if (aac_hba_setup(softs) != AACOK)
8875678Spl196000 goto error;
8885678Spl196000 attach_state |= AAC_ATTACH_SCSI_TRAN_SETUP;
8895678Spl196000
8905678Spl196000 /* Create devctl/scsi nodes for cfgadm */
8915678Spl196000 if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
8925678Spl196000 INST2DEVCTL(instance), DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
8935678Spl196000 AACDB_PRINT(softs, CE_WARN, "failed to create devctl node");
8945678Spl196000 goto error;
8955678Spl196000 }
8965678Spl196000 attach_state |= AAC_ATTACH_CREATE_DEVCTL;
8975678Spl196000
8985678Spl196000 if (ddi_create_minor_node(dip, "scsi", S_IFCHR, INST2SCSI(instance),
8995678Spl196000 DDI_NT_SCSI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
9005678Spl196000 AACDB_PRINT(softs, CE_WARN, "failed to create scsi node");
9015678Spl196000 goto error;
9025678Spl196000 }
9035678Spl196000 attach_state |= AAC_ATTACH_CREATE_SCSI;
9045678Spl196000
9055678Spl196000 /* Create aac node for app. to issue ioctls */
9065678Spl196000 if (ddi_create_minor_node(dip, "aac", S_IFCHR, INST2AAC(instance),
9075678Spl196000 DDI_PSEUDO, 0) != DDI_SUCCESS) {
9085678Spl196000 AACDB_PRINT(softs, CE_WARN, "failed to create aac node");
9095678Spl196000 goto error;
9105678Spl196000 }
9115678Spl196000
91211964SXin.Chen@Sun.COM /* Common attach is OK, so we are attached! */
91311964SXin.Chen@Sun.COM softs->state |= AAC_STATE_RUN;
91411964SXin.Chen@Sun.COM
91511964SXin.Chen@Sun.COM /* Create event thread */
91611964SXin.Chen@Sun.COM softs->fibctx_p = &softs->aifctx;
91711964SXin.Chen@Sun.COM if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
91811964SXin.Chen@Sun.COM softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
91911964SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
92011964SXin.Chen@Sun.COM softs->state &= ~AAC_STATE_RUN;
9217567SXin.Chen@Sun.COM goto error;
9227567SXin.Chen@Sun.COM }
9237567SXin.Chen@Sun.COM
9245678Spl196000 aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
9255678Spl196000
9265678Spl196000 /* Create a thread for command timeout */
92711964SXin.Chen@Sun.COM softs->timeout_id = timeout(aac_timer, (void *)softs,
92811964SXin.Chen@Sun.COM (aac_tick * drv_usectohz(1000000)));
9295678Spl196000
9305678Spl196000 /* Common attach is OK, so we are attached! */
9315678Spl196000 ddi_report_dev(dip);
9325678Spl196000 AACDB_PRINT(softs, CE_NOTE, "aac attached ok");
9335678Spl196000 return (DDI_SUCCESS);
9345678Spl196000
9355678Spl196000 error:
9365678Spl196000 if (attach_state & AAC_ATTACH_CREATE_SCSI)
9375678Spl196000 ddi_remove_minor_node(dip, "scsi");
9385678Spl196000 if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
9395678Spl196000 ddi_remove_minor_node(dip, "devctl");
9405678Spl196000 if (attach_state & AAC_ATTACH_COMM_SPACE_SETUP)
9415678Spl196000 aac_common_detach(softs);
9425678Spl196000 if (attach_state & AAC_ATTACH_SCSI_TRAN_SETUP) {
9435678Spl196000 (void) scsi_hba_detach(dip);
9445678Spl196000 scsi_hba_tran_free(AAC_DIP2TRAN(dip));
9455678Spl196000 }
9465678Spl196000 if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
94711964SXin.Chen@Sun.COM mutex_destroy(&softs->io_lock);
9485678Spl196000 mutex_destroy(&softs->q_comp_mutex);
94911964SXin.Chen@Sun.COM mutex_destroy(&softs->time_mutex);
95011964SXin.Chen@Sun.COM mutex_destroy(&softs->ev_lock);
95111964SXin.Chen@Sun.COM mutex_destroy(&softs->aifq_mutex);
9525678Spl196000 cv_destroy(&softs->event);
95311636SXin.Chen@Sun.COM cv_destroy(&softs->sync_fib_cv);
9545678Spl196000 cv_destroy(&softs->drain_cv);
95511964SXin.Chen@Sun.COM cv_destroy(&softs->event_wait_cv);
95611964SXin.Chen@Sun.COM cv_destroy(&softs->event_disp_cv);
95711964SXin.Chen@Sun.COM cv_destroy(&softs->aifq_cv);
9585678Spl196000 }
9595678Spl196000 if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
9605678Spl196000 ddi_regs_map_free(&softs->pci_mem_handle);
9615678Spl196000 aac_fm_fini(softs);
9625678Spl196000 if (attach_state & AAC_ATTACH_CARD_DETECTED)
9635678Spl196000 softs->card = AACERR;
9645678Spl196000 if (attach_state & AAC_ATTACH_SOFTSTATE_ALLOCED)
9655678Spl196000 ddi_soft_state_free(aac_softstatep, instance);
9665678Spl196000 return (DDI_FAILURE);
9675678Spl196000 }
9685678Spl196000
9695678Spl196000 static int
aac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)9705678Spl196000 aac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
9715678Spl196000 {
9725678Spl196000 scsi_hba_tran_t *tran = AAC_DIP2TRAN(dip);
9735678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
9745678Spl196000
9755678Spl196000 DBCALLED(softs, 1);
9765678Spl196000
9775678Spl196000 switch (cmd) {
9785678Spl196000 case DDI_DETACH:
9795678Spl196000 break;
9805678Spl196000 case DDI_SUSPEND:
9815678Spl196000 return (DDI_FAILURE);
9825678Spl196000 default:
9835678Spl196000 return (DDI_FAILURE);
9845678Spl196000 }
9855678Spl196000
9865678Spl196000 mutex_enter(&softs->io_lock);
9875678Spl196000 AAC_DISABLE_INTR(softs);
9885678Spl196000 softs->state = AAC_STATE_STOPPED;
9895678Spl196000
9905678Spl196000 ddi_remove_minor_node(dip, "aac");
9915678Spl196000 ddi_remove_minor_node(dip, "scsi");
9925678Spl196000 ddi_remove_minor_node(dip, "devctl");
9935678Spl196000 mutex_exit(&softs->io_lock);
9945678Spl196000
9955678Spl196000 aac_common_detach(softs);
9965678Spl196000
99711348SZhongyan.Gu@Sun.COM mutex_enter(&softs->io_lock);
9985678Spl196000 (void) scsi_hba_detach(dip);
9995678Spl196000 scsi_hba_tran_free(tran);
100011348SZhongyan.Gu@Sun.COM mutex_exit(&softs->io_lock);
10015678Spl196000
100211964SXin.Chen@Sun.COM /* Stop timer */
100311964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
100411964SXin.Chen@Sun.COM if (softs->timeout_id) {
100511964SXin.Chen@Sun.COM timeout_id_t tid = softs->timeout_id;
100611964SXin.Chen@Sun.COM softs->timeout_id = 0;
100711964SXin.Chen@Sun.COM
100811964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
100911964SXin.Chen@Sun.COM (void) untimeout(tid);
101011964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
101111964SXin.Chen@Sun.COM }
101211964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
101311964SXin.Chen@Sun.COM
101411964SXin.Chen@Sun.COM /* Destroy event thread */
101511964SXin.Chen@Sun.COM mutex_enter(&softs->ev_lock);
101611964SXin.Chen@Sun.COM cv_signal(&softs->event_disp_cv);
101711964SXin.Chen@Sun.COM cv_wait(&softs->event_wait_cv, &softs->ev_lock);
101811964SXin.Chen@Sun.COM mutex_exit(&softs->ev_lock);
101911964SXin.Chen@Sun.COM
102011964SXin.Chen@Sun.COM cv_destroy(&softs->aifq_cv);
102111964SXin.Chen@Sun.COM cv_destroy(&softs->event_disp_cv);
102211964SXin.Chen@Sun.COM cv_destroy(&softs->event_wait_cv);
102311964SXin.Chen@Sun.COM cv_destroy(&softs->drain_cv);
102411636SXin.Chen@Sun.COM cv_destroy(&softs->sync_fib_cv);
102511964SXin.Chen@Sun.COM cv_destroy(&softs->event);
10265678Spl196000 mutex_destroy(&softs->aifq_mutex);
102711964SXin.Chen@Sun.COM mutex_destroy(&softs->ev_lock);
102811964SXin.Chen@Sun.COM mutex_destroy(&softs->time_mutex);
102911964SXin.Chen@Sun.COM mutex_destroy(&softs->q_comp_mutex);
10305678Spl196000 mutex_destroy(&softs->io_lock);
10315678Spl196000
10325678Spl196000 ddi_regs_map_free(&softs->pci_mem_handle);
10335678Spl196000 aac_fm_fini(softs);
10345678Spl196000 softs->hwif = AAC_HWIF_UNKNOWN;
10355678Spl196000 softs->card = AAC_UNKNOWN_CARD;
10365678Spl196000 ddi_soft_state_free(aac_softstatep, ddi_get_instance(dip));
10375678Spl196000
10385678Spl196000 return (DDI_SUCCESS);
10395678Spl196000 }
10405678Spl196000
10415678Spl196000 /*ARGSUSED*/
10425678Spl196000 static int
aac_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)10435678Spl196000 aac_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
10445678Spl196000 {
10455678Spl196000 struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
10465678Spl196000
10475678Spl196000 DBCALLED(softs, 1);
10485678Spl196000
10495678Spl196000 mutex_enter(&softs->io_lock);
105011636SXin.Chen@Sun.COM AAC_DISABLE_INTR(softs);
10515678Spl196000 (void) aac_shutdown(softs);
10525678Spl196000 mutex_exit(&softs->io_lock);
10535678Spl196000
10545678Spl196000 return (DDI_SUCCESS);
10555678Spl196000 }
10565678Spl196000
10575678Spl196000 /*
10587656SSherry.Moore@Sun.COM * quiesce(9E) entry point.
10597656SSherry.Moore@Sun.COM *
10607656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high
10617656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be
10627656SSherry.Moore@Sun.COM * blocked.
10637656SSherry.Moore@Sun.COM *
10647656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
10657656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen.
10667656SSherry.Moore@Sun.COM */
10677656SSherry.Moore@Sun.COM static int
aac_quiesce(dev_info_t * dip)10687656SSherry.Moore@Sun.COM aac_quiesce(dev_info_t *dip)
10697656SSherry.Moore@Sun.COM {
10707656SSherry.Moore@Sun.COM struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
10717656SSherry.Moore@Sun.COM
10727656SSherry.Moore@Sun.COM if (softs == NULL)
10737656SSherry.Moore@Sun.COM return (DDI_FAILURE);
10747656SSherry.Moore@Sun.COM
107511964SXin.Chen@Sun.COM _NOTE(ASSUMING_PROTECTED(softs->state))
10767656SSherry.Moore@Sun.COM AAC_DISABLE_INTR(softs);
10777656SSherry.Moore@Sun.COM
10787656SSherry.Moore@Sun.COM return (DDI_SUCCESS);
10797656SSherry.Moore@Sun.COM }
10807656SSherry.Moore@Sun.COM
108111348SZhongyan.Gu@Sun.COM /* ARGSUSED */
108211348SZhongyan.Gu@Sun.COM static int
aac_getinfo(dev_info_t * self,ddi_info_cmd_t infocmd,void * arg,void ** result)108311348SZhongyan.Gu@Sun.COM aac_getinfo(dev_info_t *self, ddi_info_cmd_t infocmd, void *arg,
108411348SZhongyan.Gu@Sun.COM void **result)
108511348SZhongyan.Gu@Sun.COM {
108611348SZhongyan.Gu@Sun.COM int error = DDI_SUCCESS;
108711348SZhongyan.Gu@Sun.COM
108811348SZhongyan.Gu@Sun.COM switch (infocmd) {
108911348SZhongyan.Gu@Sun.COM case DDI_INFO_DEVT2INSTANCE:
109011348SZhongyan.Gu@Sun.COM *result = (void *)(intptr_t)(MINOR2INST(getminor((dev_t)arg)));
109111348SZhongyan.Gu@Sun.COM break;
109211348SZhongyan.Gu@Sun.COM default:
109311348SZhongyan.Gu@Sun.COM error = DDI_FAILURE;
109411348SZhongyan.Gu@Sun.COM }
109511348SZhongyan.Gu@Sun.COM return (error);
109611348SZhongyan.Gu@Sun.COM }
109711348SZhongyan.Gu@Sun.COM
10987656SSherry.Moore@Sun.COM /*
10995678Spl196000 * Bring the controller down to a dormant state and detach all child devices.
11005678Spl196000 * This function is called before detach or system shutdown.
11015678Spl196000 * Note: we can assume that the q_wait on the controller is empty, as we
11025678Spl196000 * won't allow shutdown if any device is open.
11035678Spl196000 */
11045678Spl196000 static int
aac_shutdown(struct aac_softstate * softs)11055678Spl196000 aac_shutdown(struct aac_softstate *softs)
11065678Spl196000 {
110711348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
110811348SZhongyan.Gu@Sun.COM struct aac_close_command *cc;
11095678Spl196000 int rval;
11105678Spl196000
111111348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
111211348SZhongyan.Gu@Sun.COM acc = softs->sync_ac.slotp->fib_acc_handle;
111311348SZhongyan.Gu@Sun.COM
111411348SZhongyan.Gu@Sun.COM cc = (struct aac_close_command *)&softs->sync_ac.slotp->fibp->data[0];
111511348SZhongyan.Gu@Sun.COM
11165678Spl196000 ddi_put32(acc, &cc->Command, VM_CloseAll);
11175678Spl196000 ddi_put32(acc, &cc->ContainerId, 0xfffffffful);
11185678Spl196000
11195678Spl196000 /* Flush all caches, set FW to write through mode */
11205678Spl196000 rval = aac_sync_fib(softs, ContainerCommand,
11215678Spl196000 AAC_FIB_SIZEOF(struct aac_close_command));
112211348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, &softs->sync_ac);
11235678Spl196000
11245678Spl196000 AACDB_PRINT(softs, CE_NOTE,
11255678Spl196000 "shutting down aac %s", (rval == AACOK) ? "ok" : "fail");
11265678Spl196000 return (rval);
11275678Spl196000 }
11285678Spl196000
11295678Spl196000 static uint_t
aac_softintr(caddr_t arg)11305678Spl196000 aac_softintr(caddr_t arg)
11315678Spl196000 {
11327100Spl196000 struct aac_softstate *softs = (void *)arg;
11335678Spl196000
11345678Spl196000 if (!AAC_IS_Q_EMPTY(&softs->q_comp)) {
11355678Spl196000 aac_drain_comp_q(softs);
113611348SZhongyan.Gu@Sun.COM }
113711348SZhongyan.Gu@Sun.COM return (DDI_INTR_CLAIMED);
11385678Spl196000 }
11395678Spl196000
11405678Spl196000 /*
11415678Spl196000 * Setup auto sense data for pkt
11425678Spl196000 */
11435678Spl196000 static void
aac_set_arq_data(struct scsi_pkt * pkt,uchar_t key,uchar_t add_code,uchar_t qual_code,uint64_t info)11445678Spl196000 aac_set_arq_data(struct scsi_pkt *pkt, uchar_t key,
11455678Spl196000 uchar_t add_code, uchar_t qual_code, uint64_t info)
11465678Spl196000 {
11477567SXin.Chen@Sun.COM struct scsi_arq_status *arqstat = (void *)(pkt->pkt_scbp);
11487567SXin.Chen@Sun.COM
11497567SXin.Chen@Sun.COM *pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
11507567SXin.Chen@Sun.COM pkt->pkt_state |= STATE_ARQ_DONE;
11517567SXin.Chen@Sun.COM
11527567SXin.Chen@Sun.COM *(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
11535678Spl196000 arqstat->sts_rqpkt_reason = CMD_CMPLT;
11545678Spl196000 arqstat->sts_rqpkt_resid = 0;
11555678Spl196000 arqstat->sts_rqpkt_state =
11565678Spl196000 STATE_GOT_BUS |
11575678Spl196000 STATE_GOT_TARGET |
11585678Spl196000 STATE_SENT_CMD |
11595678Spl196000 STATE_XFERRED_DATA;
11605678Spl196000 arqstat->sts_rqpkt_statistics = 0;
11615678Spl196000
11625678Spl196000 if (info <= 0xfffffffful) {
11635678Spl196000 arqstat->sts_sensedata.es_valid = 1;
11645678Spl196000 arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
11655678Spl196000 arqstat->sts_sensedata.es_code = CODE_FMT_FIXED_CURRENT;
11665678Spl196000 arqstat->sts_sensedata.es_key = key;
11675678Spl196000 arqstat->sts_sensedata.es_add_code = add_code;
11685678Spl196000 arqstat->sts_sensedata.es_qual_code = qual_code;
11695678Spl196000
11705678Spl196000 arqstat->sts_sensedata.es_info_1 = (info >> 24) & 0xFF;
11715678Spl196000 arqstat->sts_sensedata.es_info_2 = (info >> 16) & 0xFF;
11725678Spl196000 arqstat->sts_sensedata.es_info_3 = (info >> 8) & 0xFF;
11735678Spl196000 arqstat->sts_sensedata.es_info_4 = info & 0xFF;
11745678Spl196000 } else { /* 64-bit LBA */
11755678Spl196000 struct scsi_descr_sense_hdr *dsp;
11765678Spl196000 struct scsi_information_sense_descr *isd;
11775678Spl196000
11785678Spl196000 dsp = (struct scsi_descr_sense_hdr *)&arqstat->sts_sensedata;
11795678Spl196000 dsp->ds_class = CLASS_EXTENDED_SENSE;
11805678Spl196000 dsp->ds_code = CODE_FMT_DESCR_CURRENT;
11815678Spl196000 dsp->ds_key = key;
11825678Spl196000 dsp->ds_add_code = add_code;
11835678Spl196000 dsp->ds_qual_code = qual_code;
11845678Spl196000 dsp->ds_addl_sense_length =
11855678Spl196000 sizeof (struct scsi_information_sense_descr);
11865678Spl196000
11875678Spl196000 isd = (struct scsi_information_sense_descr *)(dsp+1);
11885678Spl196000 isd->isd_descr_type = DESCR_INFORMATION;
11895678Spl196000 isd->isd_valid = 1;
11905678Spl196000 isd->isd_information[0] = (info >> 56) & 0xFF;
11915678Spl196000 isd->isd_information[1] = (info >> 48) & 0xFF;
11925678Spl196000 isd->isd_information[2] = (info >> 40) & 0xFF;
11935678Spl196000 isd->isd_information[3] = (info >> 32) & 0xFF;
11945678Spl196000 isd->isd_information[4] = (info >> 24) & 0xFF;
11955678Spl196000 isd->isd_information[5] = (info >> 16) & 0xFF;
11965678Spl196000 isd->isd_information[6] = (info >> 8) & 0xFF;
11975678Spl196000 isd->isd_information[7] = (info) & 0xFF;
11985678Spl196000 }
11995678Spl196000 }
12005678Spl196000
12015678Spl196000 /*
12025678Spl196000 * Setup auto sense data for HARDWARE ERROR
12035678Spl196000 */
12045678Spl196000 static void
aac_set_arq_data_hwerr(struct aac_cmd * acp)12055678Spl196000 aac_set_arq_data_hwerr(struct aac_cmd *acp)
12065678Spl196000 {
12075678Spl196000 union scsi_cdb *cdbp;
12085678Spl196000 uint64_t err_blkno;
12095678Spl196000
12107100Spl196000 cdbp = (void *)acp->pkt->pkt_cdbp;
12115678Spl196000 err_blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
12125678Spl196000 aac_set_arq_data(acp->pkt, KEY_HARDWARE_ERROR, 0x00, 0x00, err_blkno);
12135678Spl196000 }
12145678Spl196000
12155678Spl196000 /*
12165678Spl196000 * Send a command to the adapter in New Comm. interface
12175678Spl196000 */
12185678Spl196000 static int
aac_send_command(struct aac_softstate * softs,struct aac_slot * slotp)12195678Spl196000 aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
12205678Spl196000 {
12215678Spl196000 uint32_t index, device;
12225678Spl196000
12235678Spl196000 index = PCI_MEM_GET32(softs, AAC_IQUE);
12245678Spl196000 if (index == 0xffffffffUL) {
12255678Spl196000 index = PCI_MEM_GET32(softs, AAC_IQUE);
12265678Spl196000 if (index == 0xffffffffUL)
12275678Spl196000 return (AACERR);
12285678Spl196000 }
12295678Spl196000
12305678Spl196000 device = index;
12315678Spl196000 PCI_MEM_PUT32(softs, device,
12325678Spl196000 (uint32_t)(slotp->fib_phyaddr & 0xfffffffful));
12335678Spl196000 device += 4;
12345678Spl196000 PCI_MEM_PUT32(softs, device, (uint32_t)(slotp->fib_phyaddr >> 32));
12355678Spl196000 device += 4;
12365678Spl196000 PCI_MEM_PUT32(softs, device, slotp->acp->fib_size);
12375678Spl196000 PCI_MEM_PUT32(softs, AAC_IQUE, index);
12385678Spl196000 return (AACOK);
12395678Spl196000 }
12405678Spl196000
12415678Spl196000 static void
aac_end_io(struct aac_softstate * softs,struct aac_cmd * acp)12425678Spl196000 aac_end_io(struct aac_softstate *softs, struct aac_cmd *acp)
12435678Spl196000 {
12447567SXin.Chen@Sun.COM struct aac_device *dvp = acp->dvp;
12455678Spl196000 int q = AAC_CMDQ(acp);
12465678Spl196000
12475678Spl196000 if (acp->slotp) { /* outstanding cmd */
124811348SZhongyan.Gu@Sun.COM if (!(acp->flags & AAC_CMD_IN_SYNC_SLOT)) {
124911348SZhongyan.Gu@Sun.COM aac_release_slot(softs, acp->slotp);
125011348SZhongyan.Gu@Sun.COM acp->slotp = NULL;
125111348SZhongyan.Gu@Sun.COM }
12525678Spl196000 if (dvp) {
12535678Spl196000 dvp->ncmds[q]--;
12545678Spl196000 if (dvp->throttle[q] == AAC_THROTTLE_DRAIN &&
12555678Spl196000 dvp->ncmds[q] == 0 && q == AAC_CMDQ_ASYNC)
12565678Spl196000 aac_set_throttle(softs, dvp, q,
12575678Spl196000 softs->total_slots);
125811348SZhongyan.Gu@Sun.COM /*
125911348SZhongyan.Gu@Sun.COM * Setup auto sense data for UNIT ATTENTION
126011348SZhongyan.Gu@Sun.COM * Each lun should generate a unit attention
126111348SZhongyan.Gu@Sun.COM * condition when reset.
126211348SZhongyan.Gu@Sun.COM * Phys. drives are treated as logical ones
126311348SZhongyan.Gu@Sun.COM * during error recovery.
126411348SZhongyan.Gu@Sun.COM */
126511348SZhongyan.Gu@Sun.COM if (dvp->type == AAC_DEV_LD) {
126611348SZhongyan.Gu@Sun.COM struct aac_container *ctp =
126711348SZhongyan.Gu@Sun.COM (struct aac_container *)dvp;
126811348SZhongyan.Gu@Sun.COM if (ctp->reset == 0)
126911348SZhongyan.Gu@Sun.COM goto noreset;
127011348SZhongyan.Gu@Sun.COM
127111348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE,
127211348SZhongyan.Gu@Sun.COM "Unit attention: reset");
127311348SZhongyan.Gu@Sun.COM ctp->reset = 0;
127411348SZhongyan.Gu@Sun.COM aac_set_arq_data(acp->pkt, KEY_UNIT_ATTENTION,
127511348SZhongyan.Gu@Sun.COM 0x29, 0x02, 0);
127611348SZhongyan.Gu@Sun.COM }
12775678Spl196000 }
127811348SZhongyan.Gu@Sun.COM noreset:
12795678Spl196000 softs->bus_ncmds[q]--;
128011348SZhongyan.Gu@Sun.COM aac_cmd_delete(&softs->q_busy, acp);
12815678Spl196000 } else { /* cmd in waiting queue */
12825678Spl196000 aac_cmd_delete(&softs->q_wait[q], acp);
12835678Spl196000 }
12845678Spl196000
12855678Spl196000 if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR))) { /* async IO */
12865678Spl196000 mutex_enter(&softs->q_comp_mutex);
12875678Spl196000 aac_cmd_enqueue(&softs->q_comp, acp);
12885678Spl196000 mutex_exit(&softs->q_comp_mutex);
12895678Spl196000 } else if (acp->flags & AAC_CMD_NO_CB) { /* sync IO */
12905678Spl196000 cv_broadcast(&softs->event);
12915678Spl196000 }
12925678Spl196000 }
12935678Spl196000
12945678Spl196000 static void
aac_handle_io(struct aac_softstate * softs,int index)12955678Spl196000 aac_handle_io(struct aac_softstate *softs, int index)
12965678Spl196000 {
12975678Spl196000 struct aac_slot *slotp;
12985678Spl196000 struct aac_cmd *acp;
12995678Spl196000 uint32_t fast;
13005678Spl196000
13015678Spl196000 fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
13025678Spl196000 index >>= 2;
13035678Spl196000
13045678Spl196000 /* Make sure firmware reported index is valid */
13055678Spl196000 ASSERT(index >= 0 && index < softs->total_slots);
13065678Spl196000 slotp = &softs->io_slot[index];
13075678Spl196000 ASSERT(slotp->index == index);
13085678Spl196000 acp = slotp->acp;
13097567SXin.Chen@Sun.COM
13107567SXin.Chen@Sun.COM if (acp == NULL || acp->slotp != slotp) {
13117567SXin.Chen@Sun.COM cmn_err(CE_WARN,
13127567SXin.Chen@Sun.COM "Firmware error: invalid slot index received from FW");
13137567SXin.Chen@Sun.COM return;
13147567SXin.Chen@Sun.COM }
13155678Spl196000
13165678Spl196000 acp->flags |= AAC_CMD_CMPLT;
13175678Spl196000 (void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
13185678Spl196000
13195678Spl196000 if (aac_check_dma_handle(slotp->fib_dma_handle) == DDI_SUCCESS) {
13205678Spl196000 /*
13215678Spl196000 * For fast response IO, the firmware do not return any FIB
13225678Spl196000 * data, so we need to fill in the FIB status and state so that
13235678Spl196000 * FIB users can handle it correctly.
13245678Spl196000 */
13255678Spl196000 if (fast) {
13265678Spl196000 uint32_t state;
13275678Spl196000
13285678Spl196000 state = ddi_get32(slotp->fib_acc_handle,
13295678Spl196000 &slotp->fibp->Header.XferState);
13305678Spl196000 /*
13315678Spl196000 * Update state for CPU not for device, no DMA sync
13325678Spl196000 * needed
13335678Spl196000 */
13345678Spl196000 ddi_put32(slotp->fib_acc_handle,
13355678Spl196000 &slotp->fibp->Header.XferState,
13365678Spl196000 state | AAC_FIBSTATE_DONEADAP);
13375678Spl196000 ddi_put32(slotp->fib_acc_handle,
13387100Spl196000 (void *)&slotp->fibp->data[0], ST_OK);
13395678Spl196000 }
13405678Spl196000
13415678Spl196000 /* Handle completed ac */
13425678Spl196000 acp->ac_comp(softs, acp);
13435678Spl196000 } else {
13445678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
13455678Spl196000 acp->flags |= AAC_CMD_ERR;
13465678Spl196000 if (acp->pkt) {
13475678Spl196000 acp->pkt->pkt_reason = CMD_TRAN_ERR;
13485678Spl196000 acp->pkt->pkt_statistics = 0;
13495678Spl196000 }
13505678Spl196000 }
13515678Spl196000 aac_end_io(softs, acp);
13525678Spl196000 }
13535678Spl196000
13545678Spl196000 /*
13555678Spl196000 * Interrupt handler for New Comm. interface
13565678Spl196000 * New Comm. interface use a different mechanism for interrupt. No explict
13575678Spl196000 * message queues, and driver need only accesses the mapped PCI mem space to
13585678Spl196000 * find the completed FIB or AIF.
13595678Spl196000 */
13605678Spl196000 static int
aac_process_intr_new(struct aac_softstate * softs)13615678Spl196000 aac_process_intr_new(struct aac_softstate *softs)
13625678Spl196000 {
13635678Spl196000 uint32_t index;
13645678Spl196000
13655678Spl196000 index = AAC_OUTB_GET(softs);
13665678Spl196000 if (index == 0xfffffffful)
13675678Spl196000 index = AAC_OUTB_GET(softs);
13685678Spl196000 if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
13695678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
13707567SXin.Chen@Sun.COM return (0);
13715678Spl196000 }
13725678Spl196000 if (index != 0xfffffffful) {
13735678Spl196000 do {
13745678Spl196000 if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
13755678Spl196000 aac_handle_io(softs, index);
13765678Spl196000 } else if (index != 0xfffffffeul) {
13775678Spl196000 struct aac_fib *fibp; /* FIB in AIF queue */
137811964SXin.Chen@Sun.COM uint16_t fib_size;
13795678Spl196000
13805678Spl196000 /*
13815678Spl196000 * 0xfffffffe means that the controller wants
13825678Spl196000 * more work, ignore it for now. Otherwise,
13835678Spl196000 * AIF received.
13845678Spl196000 */
13855678Spl196000 index &= ~2;
13865678Spl196000
138711964SXin.Chen@Sun.COM fibp = (struct aac_fib *)(softs-> \
138811964SXin.Chen@Sun.COM pci_mem_base_vaddr + index);
138911964SXin.Chen@Sun.COM fib_size = PCI_MEM_GET16(softs, index + \
13905678Spl196000 offsetof(struct aac_fib, Header.Size));
139111964SXin.Chen@Sun.COM
139211964SXin.Chen@Sun.COM aac_save_aif(softs, softs->pci_mem_handle,
139311964SXin.Chen@Sun.COM fibp, fib_size);
13945678Spl196000
13955678Spl196000 /*
13965678Spl196000 * AIF memory is owned by the adapter, so let it
13975678Spl196000 * know that we are done with it.
13985678Spl196000 */
13995678Spl196000 AAC_OUTB_SET(softs, index);
14005678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
14015678Spl196000 }
14025678Spl196000
14035678Spl196000 index = AAC_OUTB_GET(softs);
14045678Spl196000 } while (index != 0xfffffffful);
14055678Spl196000
14065678Spl196000 /*
14075678Spl196000 * Process waiting cmds before start new ones to
14085678Spl196000 * ensure first IOs are serviced first.
14095678Spl196000 */
14105678Spl196000 aac_start_waiting_io(softs);
14115678Spl196000 return (AAC_DB_COMMAND_READY);
14125678Spl196000 } else {
14135678Spl196000 return (0);
14145678Spl196000 }
14155678Spl196000 }
14165678Spl196000
14175678Spl196000 static uint_t
aac_intr_new(caddr_t arg)14185678Spl196000 aac_intr_new(caddr_t arg)
14195678Spl196000 {
14207100Spl196000 struct aac_softstate *softs = (void *)arg;
14215678Spl196000 uint_t rval;
14225678Spl196000
14235678Spl196000 mutex_enter(&softs->io_lock);
14245678Spl196000 if (aac_process_intr_new(softs))
14255678Spl196000 rval = DDI_INTR_CLAIMED;
14265678Spl196000 else
14275678Spl196000 rval = DDI_INTR_UNCLAIMED;
14285678Spl196000 mutex_exit(&softs->io_lock);
14295678Spl196000
14305678Spl196000 aac_drain_comp_q(softs);
14315678Spl196000 return (rval);
14325678Spl196000 }
14335678Spl196000
14345678Spl196000 /*
14355678Spl196000 * Interrupt handler for old interface
14365678Spl196000 * Explicit message queues are used to send FIB to and get completed FIB from
14375678Spl196000 * the adapter. Driver and adapter maitain the queues in the producer/consumer
14385678Spl196000 * manner. The driver has to query the queues to find the completed FIB.
14395678Spl196000 */
14405678Spl196000 static int
aac_process_intr_old(struct aac_softstate * softs)14415678Spl196000 aac_process_intr_old(struct aac_softstate *softs)
14425678Spl196000 {
14435678Spl196000 uint16_t status;
14445678Spl196000
14455678Spl196000 status = AAC_STATUS_GET(softs);
14465678Spl196000 if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
14475678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
14485678Spl196000 return (DDI_INTR_UNCLAIMED);
14495678Spl196000 }
14505678Spl196000 if (status & AAC_DB_RESPONSE_READY) {
14515678Spl196000 int slot_idx;
14525678Spl196000
14535678Spl196000 /* ACK the intr */
14545678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
14555678Spl196000 (void) AAC_STATUS_GET(softs);
14565678Spl196000 while (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
14575678Spl196000 &slot_idx) == AACOK)
14585678Spl196000 aac_handle_io(softs, slot_idx);
14595678Spl196000
14605678Spl196000 /*
14615678Spl196000 * Process waiting cmds before start new ones to
14625678Spl196000 * ensure first IOs are serviced first.
14635678Spl196000 */
14645678Spl196000 aac_start_waiting_io(softs);
14655678Spl196000 return (AAC_DB_RESPONSE_READY);
14665678Spl196000 } else if (status & AAC_DB_COMMAND_READY) {
14675678Spl196000 int aif_idx;
14685678Spl196000
14695678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
14705678Spl196000 (void) AAC_STATUS_GET(softs);
14715678Spl196000 if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
14725678Spl196000 AACOK) {
14735678Spl196000 ddi_acc_handle_t acc = softs->comm_space_acc_handle;
147411964SXin.Chen@Sun.COM struct aac_fib *fibp; /* FIB in communication space */
147511964SXin.Chen@Sun.COM uint16_t fib_size;
14765678Spl196000 uint32_t fib_xfer_state;
14775678Spl196000 uint32_t addr, size;
14785678Spl196000
14795678Spl196000 ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
14805678Spl196000
14815678Spl196000 #define AAC_SYNC_AIF(softs, aif_idx, type) \
14825678Spl196000 { (void) ddi_dma_sync((softs)->comm_space_dma_handle, \
14835678Spl196000 offsetof(struct aac_comm_space, \
14845678Spl196000 adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
14855678Spl196000 (type)); }
14865678Spl196000
14875678Spl196000 /* Copy AIF from adapter to the empty AIF slot */
14885678Spl196000 AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
148911964SXin.Chen@Sun.COM fibp = &softs->comm_space->adapter_fibs[aif_idx];
149011964SXin.Chen@Sun.COM fib_size = ddi_get16(acc, &fibp->Header.Size);
149111964SXin.Chen@Sun.COM
149211964SXin.Chen@Sun.COM aac_save_aif(softs, acc, fibp, fib_size);
14935678Spl196000
14945678Spl196000 /* Complete AIF back to adapter with good status */
14955678Spl196000 fib_xfer_state = LE_32(fibp->Header.XferState);
14965678Spl196000 if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
149711964SXin.Chen@Sun.COM ddi_put32(acc, &fibp->Header.XferState,
14985678Spl196000 fib_xfer_state | AAC_FIBSTATE_DONEHOST);
149911964SXin.Chen@Sun.COM ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
150011964SXin.Chen@Sun.COM if (fib_size > AAC_FIB_SIZE)
150111964SXin.Chen@Sun.COM ddi_put16(acc, &fibp->Header.Size,
15025678Spl196000 AAC_FIB_SIZE);
15035678Spl196000 AAC_SYNC_AIF(softs, aif_idx,
15045678Spl196000 DDI_DMA_SYNC_FORDEV);
15055678Spl196000 }
15065678Spl196000
15075678Spl196000 /* Put the AIF response on the response queue */
15085678Spl196000 addr = ddi_get32(acc,
15095678Spl196000 &softs->comm_space->adapter_fibs[aif_idx]. \
15105678Spl196000 Header.SenderFibAddress);
15115678Spl196000 size = (uint32_t)ddi_get16(acc,
15125678Spl196000 &softs->comm_space->adapter_fibs[aif_idx]. \
15135678Spl196000 Header.Size);
15145678Spl196000 ddi_put32(acc,
15155678Spl196000 &softs->comm_space->adapter_fibs[aif_idx]. \
15165678Spl196000 Header.ReceiverFibAddress, addr);
15175678Spl196000 if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
15185678Spl196000 addr, size) == AACERR)
15195678Spl196000 cmn_err(CE_NOTE, "!AIF ack failed");
15205678Spl196000 }
15215678Spl196000 return (AAC_DB_COMMAND_READY);
15225678Spl196000 } else if (status & AAC_DB_PRINTF_READY) {
15235678Spl196000 /* ACK the intr */
15245678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
15255678Spl196000 (void) AAC_STATUS_GET(softs);
15265678Spl196000 (void) ddi_dma_sync(softs->comm_space_dma_handle,
15275678Spl196000 offsetof(struct aac_comm_space, adapter_print_buf),
15285678Spl196000 AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
15295678Spl196000 if (aac_check_dma_handle(softs->comm_space_dma_handle) ==
15305678Spl196000 DDI_SUCCESS)
15315678Spl196000 cmn_err(CE_NOTE, "MSG From Adapter: %s",
15325678Spl196000 softs->comm_space->adapter_print_buf);
15335678Spl196000 else
15345678Spl196000 ddi_fm_service_impact(softs->devinfo_p,
15355678Spl196000 DDI_SERVICE_UNAFFECTED);
15365678Spl196000 AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
15375678Spl196000 return (AAC_DB_PRINTF_READY);
15385678Spl196000 } else if (status & AAC_DB_COMMAND_NOT_FULL) {
15395678Spl196000 /*
15405678Spl196000 * Without these two condition statements, the OS could hang
15415678Spl196000 * after a while, especially if there are a lot of AIF's to
15425678Spl196000 * handle, for instance if a drive is pulled from an array
15435678Spl196000 * under heavy load.
15445678Spl196000 */
15455678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
15465678Spl196000 return (AAC_DB_COMMAND_NOT_FULL);
15475678Spl196000 } else if (status & AAC_DB_RESPONSE_NOT_FULL) {
15485678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
15495678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_NOT_FULL);
15505678Spl196000 return (AAC_DB_RESPONSE_NOT_FULL);
15515678Spl196000 } else {
15525678Spl196000 return (0);
15535678Spl196000 }
15545678Spl196000 }
15555678Spl196000
15565678Spl196000 static uint_t
aac_intr_old(caddr_t arg)15575678Spl196000 aac_intr_old(caddr_t arg)
15585678Spl196000 {
15597100Spl196000 struct aac_softstate *softs = (void *)arg;
15605678Spl196000 int rval;
15615678Spl196000
15625678Spl196000 mutex_enter(&softs->io_lock);
15635678Spl196000 if (aac_process_intr_old(softs))
15645678Spl196000 rval = DDI_INTR_CLAIMED;
15655678Spl196000 else
15665678Spl196000 rval = DDI_INTR_UNCLAIMED;
15675678Spl196000 mutex_exit(&softs->io_lock);
15685678Spl196000
15695678Spl196000 aac_drain_comp_q(softs);
15705678Spl196000 return (rval);
15715678Spl196000 }
15725678Spl196000
15735678Spl196000 /*
15747000Sjd218194 * Query FIXED or MSI interrupts
15757000Sjd218194 */
15767000Sjd218194 static int
aac_query_intrs(struct aac_softstate * softs,int intr_type)15777000Sjd218194 aac_query_intrs(struct aac_softstate *softs, int intr_type)
15787000Sjd218194 {
15797000Sjd218194 dev_info_t *dip = softs->devinfo_p;
158011348SZhongyan.Gu@Sun.COM int avail, actual, count;
15817000Sjd218194 int i, flag, ret;
15827000Sjd218194
15837000Sjd218194 AACDB_PRINT(softs, CE_NOTE,
15847000Sjd218194 "aac_query_intrs:interrupt type 0x%x", intr_type);
15857000Sjd218194
15867000Sjd218194 /* Get number of interrupts */
15877000Sjd218194 ret = ddi_intr_get_nintrs(dip, intr_type, &count);
15887000Sjd218194 if ((ret != DDI_SUCCESS) || (count == 0)) {
15897000Sjd218194 AACDB_PRINT(softs, CE_WARN,
15907000Sjd218194 "ddi_intr_get_nintrs() failed, ret %d count %d",
15917000Sjd218194 ret, count);
15927000Sjd218194 return (DDI_FAILURE);
15937000Sjd218194 }
15947000Sjd218194
15957000Sjd218194 /* Get number of available interrupts */
15967000Sjd218194 ret = ddi_intr_get_navail(dip, intr_type, &avail);
15977000Sjd218194 if ((ret != DDI_SUCCESS) || (avail == 0)) {
15987000Sjd218194 AACDB_PRINT(softs, CE_WARN,
15997000Sjd218194 "ddi_intr_get_navail() failed, ret %d avail %d",
16007000Sjd218194 ret, avail);
16017000Sjd218194 return (DDI_FAILURE);
16027000Sjd218194 }
16037000Sjd218194
16047000Sjd218194 AACDB_PRINT(softs, CE_NOTE,
16057000Sjd218194 "ddi_intr_get_nvail returned %d, navail() returned %d",
16067000Sjd218194 count, avail);
16077000Sjd218194
16087000Sjd218194 /* Allocate an array of interrupt handles */
160911348SZhongyan.Gu@Sun.COM softs->intr_size = count * sizeof (ddi_intr_handle_t);
161011348SZhongyan.Gu@Sun.COM softs->htable = kmem_alloc(softs->intr_size, KM_SLEEP);
16117000Sjd218194
16127000Sjd218194 if (intr_type == DDI_INTR_TYPE_MSI) {
16137000Sjd218194 count = 1; /* only one vector needed by now */
16147000Sjd218194 flag = DDI_INTR_ALLOC_STRICT;
16157000Sjd218194 } else { /* must be DDI_INTR_TYPE_FIXED */
16167000Sjd218194 flag = DDI_INTR_ALLOC_NORMAL;
16177000Sjd218194 }
16187000Sjd218194
16197000Sjd218194 /* Call ddi_intr_alloc() */
16207000Sjd218194 ret = ddi_intr_alloc(dip, softs->htable, intr_type, 0,
16217000Sjd218194 count, &actual, flag);
16227000Sjd218194
16237000Sjd218194 if ((ret != DDI_SUCCESS) || (actual == 0)) {
16247000Sjd218194 AACDB_PRINT(softs, CE_WARN,
16257000Sjd218194 "ddi_intr_alloc() failed, ret = %d", ret);
16267000Sjd218194 actual = 0;
16277000Sjd218194 goto error;
16287000Sjd218194 }
16297000Sjd218194
16307000Sjd218194 if (actual < count) {
16317000Sjd218194 AACDB_PRINT(softs, CE_NOTE,
16327000Sjd218194 "Requested: %d, Received: %d", count, actual);
16337000Sjd218194 goto error;
16347000Sjd218194 }
16357000Sjd218194
16367000Sjd218194 softs->intr_cnt = actual;
16377000Sjd218194
16387000Sjd218194 /* Get priority for first msi, assume remaining are all the same */
16397000Sjd218194 if ((ret = ddi_intr_get_pri(softs->htable[0],
16407000Sjd218194 &softs->intr_pri)) != DDI_SUCCESS) {
16417000Sjd218194 AACDB_PRINT(softs, CE_WARN,
16427000Sjd218194 "ddi_intr_get_pri() failed, ret = %d", ret);
16437000Sjd218194 goto error;
16447000Sjd218194 }
16457000Sjd218194
16467000Sjd218194 /* Test for high level mutex */
16477000Sjd218194 if (softs->intr_pri >= ddi_intr_get_hilevel_pri()) {
16487000Sjd218194 AACDB_PRINT(softs, CE_WARN,
16497000Sjd218194 "aac_query_intrs: Hi level interrupt not supported");
16507000Sjd218194 goto error;
16517000Sjd218194 }
16527000Sjd218194
16537000Sjd218194 return (DDI_SUCCESS);
16547000Sjd218194
16557000Sjd218194 error:
16567000Sjd218194 /* Free already allocated intr */
16577000Sjd218194 for (i = 0; i < actual; i++)
16587000Sjd218194 (void) ddi_intr_free(softs->htable[i]);
16597000Sjd218194
166011348SZhongyan.Gu@Sun.COM kmem_free(softs->htable, softs->intr_size);
16617000Sjd218194 return (DDI_FAILURE);
16627000Sjd218194 }
16637000Sjd218194
166410175SStuart.Maybee@Sun.COM
16657000Sjd218194 /*
16667000Sjd218194 * Register FIXED or MSI interrupts, and enable them
16677000Sjd218194 */
16687000Sjd218194 static int
aac_add_intrs(struct aac_softstate * softs)16697000Sjd218194 aac_add_intrs(struct aac_softstate *softs)
16707000Sjd218194 {
16717000Sjd218194 int i, ret;
167211348SZhongyan.Gu@Sun.COM int actual;
16737000Sjd218194 ddi_intr_handler_t *aac_intr;
16747000Sjd218194
16757000Sjd218194 actual = softs->intr_cnt;
16767000Sjd218194 aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
16777000Sjd218194 aac_intr_new : aac_intr_old);
16787000Sjd218194
16797000Sjd218194 /* Call ddi_intr_add_handler() */
16807000Sjd218194 for (i = 0; i < actual; i++) {
16817000Sjd218194 if ((ret = ddi_intr_add_handler(softs->htable[i],
16827000Sjd218194 aac_intr, (caddr_t)softs, NULL)) != DDI_SUCCESS) {
16837000Sjd218194 cmn_err(CE_WARN,
16847000Sjd218194 "ddi_intr_add_handler() failed ret = %d", ret);
16857000Sjd218194
16867000Sjd218194 /* Free already allocated intr */
16877000Sjd218194 for (i = 0; i < actual; i++)
16887000Sjd218194 (void) ddi_intr_free(softs->htable[i]);
16897000Sjd218194
169011348SZhongyan.Gu@Sun.COM kmem_free(softs->htable, softs->intr_size);
16917000Sjd218194 return (DDI_FAILURE);
16927000Sjd218194 }
16937000Sjd218194 }
16947000Sjd218194
16957000Sjd218194 if ((ret = ddi_intr_get_cap(softs->htable[0], &softs->intr_cap))
16967000Sjd218194 != DDI_SUCCESS) {
16977000Sjd218194 cmn_err(CE_WARN, "ddi_intr_get_cap() failed, ret = %d", ret);
16987000Sjd218194
16997000Sjd218194 /* Free already allocated intr */
17007000Sjd218194 for (i = 0; i < actual; i++)
17017000Sjd218194 (void) ddi_intr_free(softs->htable[i]);
17027000Sjd218194
170311348SZhongyan.Gu@Sun.COM kmem_free(softs->htable, softs->intr_size);
17047000Sjd218194 return (DDI_FAILURE);
17057000Sjd218194 }
17067000Sjd218194
17077000Sjd218194 return (DDI_SUCCESS);
17087000Sjd218194 }
17097000Sjd218194
17107000Sjd218194 /*
17117000Sjd218194 * Unregister FIXED or MSI interrupts
17127000Sjd218194 */
17137000Sjd218194 static void
aac_remove_intrs(struct aac_softstate * softs)17147000Sjd218194 aac_remove_intrs(struct aac_softstate *softs)
17157000Sjd218194 {
17167000Sjd218194 int i;
17177000Sjd218194
17187000Sjd218194 /* Disable all interrupts */
171911348SZhongyan.Gu@Sun.COM (void) aac_disable_intrs(softs);
17207000Sjd218194 /* Call ddi_intr_remove_handler() */
17217000Sjd218194 for (i = 0; i < softs->intr_cnt; i++) {
17227000Sjd218194 (void) ddi_intr_remove_handler(softs->htable[i]);
17237000Sjd218194 (void) ddi_intr_free(softs->htable[i]);
17247000Sjd218194 }
17257000Sjd218194
172611348SZhongyan.Gu@Sun.COM kmem_free(softs->htable, softs->intr_size);
172711348SZhongyan.Gu@Sun.COM }
172811348SZhongyan.Gu@Sun.COM
172911348SZhongyan.Gu@Sun.COM static int
aac_enable_intrs(struct aac_softstate * softs)173011348SZhongyan.Gu@Sun.COM aac_enable_intrs(struct aac_softstate *softs)
173111348SZhongyan.Gu@Sun.COM {
173211348SZhongyan.Gu@Sun.COM int rval = AACOK;
173311348SZhongyan.Gu@Sun.COM
173411348SZhongyan.Gu@Sun.COM if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
173511348SZhongyan.Gu@Sun.COM /* for MSI block enable */
173611348SZhongyan.Gu@Sun.COM if (ddi_intr_block_enable(softs->htable, softs->intr_cnt) !=
173711348SZhongyan.Gu@Sun.COM DDI_SUCCESS)
173811348SZhongyan.Gu@Sun.COM rval = AACERR;
173911348SZhongyan.Gu@Sun.COM } else {
174011348SZhongyan.Gu@Sun.COM int i;
174111348SZhongyan.Gu@Sun.COM
174211348SZhongyan.Gu@Sun.COM /* Call ddi_intr_enable() for legacy/MSI non block enable */
174311348SZhongyan.Gu@Sun.COM for (i = 0; i < softs->intr_cnt; i++) {
174411348SZhongyan.Gu@Sun.COM if (ddi_intr_enable(softs->htable[i]) != DDI_SUCCESS)
174511348SZhongyan.Gu@Sun.COM rval = AACERR;
174611348SZhongyan.Gu@Sun.COM }
174711348SZhongyan.Gu@Sun.COM }
174811348SZhongyan.Gu@Sun.COM return (rval);
174911348SZhongyan.Gu@Sun.COM }
175011348SZhongyan.Gu@Sun.COM
175111348SZhongyan.Gu@Sun.COM static int
aac_disable_intrs(struct aac_softstate * softs)175211348SZhongyan.Gu@Sun.COM aac_disable_intrs(struct aac_softstate *softs)
175311348SZhongyan.Gu@Sun.COM {
175411348SZhongyan.Gu@Sun.COM int rval = AACOK;
175511348SZhongyan.Gu@Sun.COM
175611348SZhongyan.Gu@Sun.COM if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
175711348SZhongyan.Gu@Sun.COM /* Call ddi_intr_block_disable() */
175811348SZhongyan.Gu@Sun.COM if (ddi_intr_block_disable(softs->htable, softs->intr_cnt) !=
175911348SZhongyan.Gu@Sun.COM DDI_SUCCESS)
176011348SZhongyan.Gu@Sun.COM rval = AACERR;
176111348SZhongyan.Gu@Sun.COM } else {
176211348SZhongyan.Gu@Sun.COM int i;
176311348SZhongyan.Gu@Sun.COM
176411348SZhongyan.Gu@Sun.COM for (i = 0; i < softs->intr_cnt; i++) {
176511348SZhongyan.Gu@Sun.COM if (ddi_intr_disable(softs->htable[i]) != DDI_SUCCESS)
176611348SZhongyan.Gu@Sun.COM rval = AACERR;
176711348SZhongyan.Gu@Sun.COM }
176811348SZhongyan.Gu@Sun.COM }
176911348SZhongyan.Gu@Sun.COM return (rval);
17707000Sjd218194 }
17717000Sjd218194
17727000Sjd218194 /*
17735678Spl196000 * Set pkt_reason and OR in pkt_statistics flag
17745678Spl196000 */
17755678Spl196000 static void
aac_set_pkt_reason(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason,uint_t stat)17765678Spl196000 aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
17775678Spl196000 uchar_t reason, uint_t stat)
17785678Spl196000 {
17795678Spl196000 #ifndef __lock_lint
17805678Spl196000 _NOTE(ARGUNUSED(softs))
17815678Spl196000 #endif
17825678Spl196000 if (acp->pkt->pkt_reason == CMD_CMPLT)
17835678Spl196000 acp->pkt->pkt_reason = reason;
17845678Spl196000 acp->pkt->pkt_statistics |= stat;
17855678Spl196000 }
17865678Spl196000
17875678Spl196000 /*
17885678Spl196000 * Handle a finished pkt of soft SCMD
17895678Spl196000 */
17905678Spl196000 static void
aac_soft_callback(struct aac_softstate * softs,struct aac_cmd * acp)17915678Spl196000 aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
17925678Spl196000 {
17935678Spl196000 ASSERT(acp->pkt);
17945678Spl196000
17955678Spl196000 acp->flags |= AAC_CMD_CMPLT;
17965678Spl196000
17975678Spl196000 acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
17987567SXin.Chen@Sun.COM STATE_SENT_CMD | STATE_GOT_STATUS;
17995678Spl196000 if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
18005678Spl196000 acp->pkt->pkt_resid = 0;
18015678Spl196000
18025678Spl196000 /* AAC_CMD_NO_INTR means no complete callback */
18035678Spl196000 if (!(acp->flags & AAC_CMD_NO_INTR)) {
18045678Spl196000 mutex_enter(&softs->q_comp_mutex);
18055678Spl196000 aac_cmd_enqueue(&softs->q_comp, acp);
18065678Spl196000 mutex_exit(&softs->q_comp_mutex);
18075678Spl196000 ddi_trigger_softintr(softs->softint_id);
18085678Spl196000 }
18095678Spl196000 }
18105678Spl196000
18115678Spl196000 /*
18125678Spl196000 * Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
18135678Spl196000 */
18145678Spl196000
18155678Spl196000 /*
18165678Spl196000 * Handle completed logical device IO command
18175678Spl196000 */
18185678Spl196000 /*ARGSUSED*/
18195678Spl196000 static void
aac_ld_complete(struct aac_softstate * softs,struct aac_cmd * acp)18205678Spl196000 aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
18215678Spl196000 {
18225678Spl196000 struct aac_slot *slotp = acp->slotp;
18235678Spl196000 struct aac_blockread_response *resp;
18245678Spl196000 uint32_t status;
18255678Spl196000
18265678Spl196000 ASSERT(!(acp->flags & AAC_CMD_SYNC));
18275678Spl196000 ASSERT(!(acp->flags & AAC_CMD_NO_CB));
18285678Spl196000
18297567SXin.Chen@Sun.COM acp->pkt->pkt_state |= STATE_GOT_STATUS;
18307567SXin.Chen@Sun.COM
18315678Spl196000 /*
18325678Spl196000 * block_read/write has a similar response header, use blockread
18335678Spl196000 * response for both.
18345678Spl196000 */
18355678Spl196000 resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
18365678Spl196000 status = ddi_get32(slotp->fib_acc_handle, &resp->Status);
18375678Spl196000 if (status == ST_OK) {
18385678Spl196000 acp->pkt->pkt_resid = 0;
18395678Spl196000 acp->pkt->pkt_state |= STATE_XFERRED_DATA;
18405678Spl196000 } else {
18415678Spl196000 aac_set_arq_data_hwerr(acp);
18425678Spl196000 }
18435678Spl196000 }
18445678Spl196000
18455678Spl196000 /*
18467567SXin.Chen@Sun.COM * Handle completed phys. device IO command
18477567SXin.Chen@Sun.COM */
18487567SXin.Chen@Sun.COM static void
aac_pd_complete(struct aac_softstate * softs,struct aac_cmd * acp)18497567SXin.Chen@Sun.COM aac_pd_complete(struct aac_softstate *softs, struct aac_cmd *acp)
18507567SXin.Chen@Sun.COM {
18517567SXin.Chen@Sun.COM ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
18527567SXin.Chen@Sun.COM struct aac_fib *fibp = acp->slotp->fibp;
18537567SXin.Chen@Sun.COM struct scsi_pkt *pkt = acp->pkt;
18547567SXin.Chen@Sun.COM struct aac_srb_reply *resp;
18557567SXin.Chen@Sun.COM uint32_t resp_status;
18567567SXin.Chen@Sun.COM
18577567SXin.Chen@Sun.COM ASSERT(!(acp->flags & AAC_CMD_SYNC));
18587567SXin.Chen@Sun.COM ASSERT(!(acp->flags & AAC_CMD_NO_CB));
18597567SXin.Chen@Sun.COM
18607567SXin.Chen@Sun.COM resp = (struct aac_srb_reply *)&fibp->data[0];
18617567SXin.Chen@Sun.COM resp_status = ddi_get32(acc, &resp->status);
18627567SXin.Chen@Sun.COM
18637567SXin.Chen@Sun.COM /* First check FIB status */
18647567SXin.Chen@Sun.COM if (resp_status == ST_OK) {
18657567SXin.Chen@Sun.COM uint32_t scsi_status;
18667567SXin.Chen@Sun.COM uint32_t srb_status;
18677567SXin.Chen@Sun.COM uint32_t data_xfer_length;
18687567SXin.Chen@Sun.COM
18697567SXin.Chen@Sun.COM scsi_status = ddi_get32(acc, &resp->scsi_status);
18707567SXin.Chen@Sun.COM srb_status = ddi_get32(acc, &resp->srb_status);
18717567SXin.Chen@Sun.COM data_xfer_length = ddi_get32(acc, &resp->data_xfer_length);
18727567SXin.Chen@Sun.COM
18737567SXin.Chen@Sun.COM *pkt->pkt_scbp = (uint8_t)scsi_status;
18747567SXin.Chen@Sun.COM pkt->pkt_state |= STATE_GOT_STATUS;
18757567SXin.Chen@Sun.COM if (scsi_status == STATUS_GOOD) {
18767567SXin.Chen@Sun.COM uchar_t cmd = ((union scsi_cdb *)(void *)
18777567SXin.Chen@Sun.COM (pkt->pkt_cdbp))->scc_cmd;
18787567SXin.Chen@Sun.COM
18797567SXin.Chen@Sun.COM /* Next check SRB status */
18807567SXin.Chen@Sun.COM switch (srb_status & 0x3f) {
18817567SXin.Chen@Sun.COM case SRB_STATUS_DATA_OVERRUN:
18827567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "DATA_OVERRUN: " \
18837567SXin.Chen@Sun.COM "scmd=%d, xfer=%d, buflen=%d",
18847567SXin.Chen@Sun.COM (uint32_t)cmd, data_xfer_length,
18857567SXin.Chen@Sun.COM acp->bcount);
18867567SXin.Chen@Sun.COM
18877567SXin.Chen@Sun.COM switch (cmd) {
18887567SXin.Chen@Sun.COM case SCMD_READ:
18897567SXin.Chen@Sun.COM case SCMD_WRITE:
18907567SXin.Chen@Sun.COM case SCMD_READ_G1:
18917567SXin.Chen@Sun.COM case SCMD_WRITE_G1:
18927567SXin.Chen@Sun.COM case SCMD_READ_G4:
18937567SXin.Chen@Sun.COM case SCMD_WRITE_G4:
18947567SXin.Chen@Sun.COM case SCMD_READ_G5:
18957567SXin.Chen@Sun.COM case SCMD_WRITE_G5:
18967567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp,
18977567SXin.Chen@Sun.COM CMD_DATA_OVR, 0);
18987567SXin.Chen@Sun.COM break;
18997567SXin.Chen@Sun.COM }
19007567SXin.Chen@Sun.COM /*FALLTHRU*/
19017567SXin.Chen@Sun.COM case SRB_STATUS_ERROR_RECOVERY:
19027567SXin.Chen@Sun.COM case SRB_STATUS_PENDING:
19037567SXin.Chen@Sun.COM case SRB_STATUS_SUCCESS:
19047567SXin.Chen@Sun.COM /*
19057567SXin.Chen@Sun.COM * pkt_resid should only be calculated if the
19067567SXin.Chen@Sun.COM * status is ERROR_RECOVERY/PENDING/SUCCESS/
19077567SXin.Chen@Sun.COM * OVERRUN/UNDERRUN
19087567SXin.Chen@Sun.COM */
19097567SXin.Chen@Sun.COM if (data_xfer_length) {
19107567SXin.Chen@Sun.COM pkt->pkt_state |= STATE_XFERRED_DATA;
19117567SXin.Chen@Sun.COM pkt->pkt_resid = acp->bcount - \
19127567SXin.Chen@Sun.COM data_xfer_length;
19137567SXin.Chen@Sun.COM ASSERT(pkt->pkt_resid >= 0);
19147567SXin.Chen@Sun.COM }
19157567SXin.Chen@Sun.COM break;
19167567SXin.Chen@Sun.COM case SRB_STATUS_ABORTED:
19177567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
19187567SXin.Chen@Sun.COM "SRB_STATUS_ABORTED, xfer=%d, resid=%d",
19197567SXin.Chen@Sun.COM data_xfer_length, pkt->pkt_resid);
19207567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_ABORTED,
19217567SXin.Chen@Sun.COM STAT_ABORTED);
19227567SXin.Chen@Sun.COM break;
19237567SXin.Chen@Sun.COM case SRB_STATUS_ABORT_FAILED:
19247567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
19257567SXin.Chen@Sun.COM "SRB_STATUS_ABORT_FAILED, xfer=%d, " \
19267567SXin.Chen@Sun.COM "resid=%d", data_xfer_length,
19277567SXin.Chen@Sun.COM pkt->pkt_resid);
19287567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_ABORT_FAIL,
19297567SXin.Chen@Sun.COM 0);
19307567SXin.Chen@Sun.COM break;
19317567SXin.Chen@Sun.COM case SRB_STATUS_PARITY_ERROR:
19327567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
19337567SXin.Chen@Sun.COM "SRB_STATUS_PARITY_ERROR, xfer=%d, " \
19347567SXin.Chen@Sun.COM "resid=%d", data_xfer_length,
19357567SXin.Chen@Sun.COM pkt->pkt_resid);
19367567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_PER_FAIL, 0);
19377567SXin.Chen@Sun.COM break;
19387567SXin.Chen@Sun.COM case SRB_STATUS_NO_DEVICE:
19397567SXin.Chen@Sun.COM case SRB_STATUS_INVALID_PATH_ID:
19407567SXin.Chen@Sun.COM case SRB_STATUS_INVALID_TARGET_ID:
19417567SXin.Chen@Sun.COM case SRB_STATUS_INVALID_LUN:
19427567SXin.Chen@Sun.COM case SRB_STATUS_SELECTION_TIMEOUT:
19437567SXin.Chen@Sun.COM #ifdef DEBUG
19447567SXin.Chen@Sun.COM if (AAC_DEV_IS_VALID(acp->dvp)) {
19457567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
19467567SXin.Chen@Sun.COM "SRB_STATUS_NO_DEVICE(%d), " \
19477567SXin.Chen@Sun.COM "xfer=%d, resid=%d ",
19487567SXin.Chen@Sun.COM srb_status & 0x3f,
19497567SXin.Chen@Sun.COM data_xfer_length, pkt->pkt_resid);
19507567SXin.Chen@Sun.COM }
19517567SXin.Chen@Sun.COM #endif
19527567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_DEV_GONE, 0);
19537567SXin.Chen@Sun.COM break;
19547567SXin.Chen@Sun.COM case SRB_STATUS_COMMAND_TIMEOUT:
19557567SXin.Chen@Sun.COM case SRB_STATUS_TIMEOUT:
19567567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
19577567SXin.Chen@Sun.COM "SRB_STATUS_COMMAND_TIMEOUT, xfer=%d, " \
19587567SXin.Chen@Sun.COM "resid=%d", data_xfer_length,
19597567SXin.Chen@Sun.COM pkt->pkt_resid);
19607567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
19617567SXin.Chen@Sun.COM STAT_TIMEOUT);
19627567SXin.Chen@Sun.COM break;
19637567SXin.Chen@Sun.COM case SRB_STATUS_BUS_RESET:
19647567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
19657567SXin.Chen@Sun.COM "SRB_STATUS_BUS_RESET, xfer=%d, " \
19667567SXin.Chen@Sun.COM "resid=%d", data_xfer_length,
19677567SXin.Chen@Sun.COM pkt->pkt_resid);
19687567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_RESET,
19697567SXin.Chen@Sun.COM STAT_BUS_RESET);
19707567SXin.Chen@Sun.COM break;
19717567SXin.Chen@Sun.COM default:
19727567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "srb_status=%d, " \
19737567SXin.Chen@Sun.COM "xfer=%d, resid=%d", srb_status & 0x3f,
19747567SXin.Chen@Sun.COM data_xfer_length, pkt->pkt_resid);
19757567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
19767567SXin.Chen@Sun.COM break;
19777567SXin.Chen@Sun.COM }
19787567SXin.Chen@Sun.COM } else if (scsi_status == STATUS_CHECK) {
19797567SXin.Chen@Sun.COM /* CHECK CONDITION */
19807567SXin.Chen@Sun.COM struct scsi_arq_status *arqstat =
19817567SXin.Chen@Sun.COM (void *)(pkt->pkt_scbp);
19827567SXin.Chen@Sun.COM uint32_t sense_data_size;
19837567SXin.Chen@Sun.COM
19847567SXin.Chen@Sun.COM pkt->pkt_state |= STATE_ARQ_DONE;
19857567SXin.Chen@Sun.COM
19867567SXin.Chen@Sun.COM *(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
19877567SXin.Chen@Sun.COM arqstat->sts_rqpkt_reason = CMD_CMPLT;
19887567SXin.Chen@Sun.COM arqstat->sts_rqpkt_resid = 0;
19897567SXin.Chen@Sun.COM arqstat->sts_rqpkt_state =
19907567SXin.Chen@Sun.COM STATE_GOT_BUS |
19917567SXin.Chen@Sun.COM STATE_GOT_TARGET |
19927567SXin.Chen@Sun.COM STATE_SENT_CMD |
19937567SXin.Chen@Sun.COM STATE_XFERRED_DATA;
19947567SXin.Chen@Sun.COM arqstat->sts_rqpkt_statistics = 0;
19957567SXin.Chen@Sun.COM
19967567SXin.Chen@Sun.COM sense_data_size = ddi_get32(acc,
19977567SXin.Chen@Sun.COM &resp->sense_data_size);
19987567SXin.Chen@Sun.COM ASSERT(sense_data_size <= AAC_SENSE_BUFFERSIZE);
19997567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
20007567SXin.Chen@Sun.COM "CHECK CONDITION: sense len=%d, xfer len=%d",
20017567SXin.Chen@Sun.COM sense_data_size, data_xfer_length);
20027567SXin.Chen@Sun.COM
20037567SXin.Chen@Sun.COM if (sense_data_size > SENSE_LENGTH)
20047567SXin.Chen@Sun.COM sense_data_size = SENSE_LENGTH;
20057567SXin.Chen@Sun.COM ddi_rep_get8(acc, (uint8_t *)&arqstat->sts_sensedata,
20067567SXin.Chen@Sun.COM (uint8_t *)resp->sense_data, sense_data_size,
20077567SXin.Chen@Sun.COM DDI_DEV_AUTOINCR);
20087567SXin.Chen@Sun.COM } else {
20097567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "invaild scsi status: " \
20107567SXin.Chen@Sun.COM "scsi_status=%d, srb_status=%d",
20117567SXin.Chen@Sun.COM scsi_status, srb_status);
20127567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
20137567SXin.Chen@Sun.COM }
20147567SXin.Chen@Sun.COM } else {
20157567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "SRB failed: fib status %d",
20167567SXin.Chen@Sun.COM resp_status);
20177567SXin.Chen@Sun.COM aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
20187567SXin.Chen@Sun.COM }
20197567SXin.Chen@Sun.COM }
20207567SXin.Chen@Sun.COM
20217567SXin.Chen@Sun.COM /*
20225678Spl196000 * Handle completed IOCTL command
20235678Spl196000 */
20245678Spl196000 /*ARGSUSED*/
20255678Spl196000 void
aac_ioctl_complete(struct aac_softstate * softs,struct aac_cmd * acp)20265678Spl196000 aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
20275678Spl196000 {
20285678Spl196000 struct aac_slot *slotp = acp->slotp;
20295678Spl196000
20305678Spl196000 /*
20315678Spl196000 * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
20325678Spl196000 * may wait on softs->event, so use cv_broadcast() instead
20335678Spl196000 * of cv_signal().
20345678Spl196000 */
20355678Spl196000 ASSERT(acp->flags & AAC_CMD_SYNC);
20365678Spl196000 ASSERT(acp->flags & AAC_CMD_NO_CB);
20375678Spl196000
20385678Spl196000 /* Get the size of the response FIB from its FIB.Header.Size field */
20395678Spl196000 acp->fib_size = ddi_get16(slotp->fib_acc_handle,
20405678Spl196000 &slotp->fibp->Header.Size);
20415678Spl196000
20425678Spl196000 ASSERT(acp->fib_size <= softs->aac_max_fib_size);
20435678Spl196000 ddi_rep_get8(slotp->fib_acc_handle, (uint8_t *)acp->fibp,
20445678Spl196000 (uint8_t *)slotp->fibp, acp->fib_size, DDI_DEV_AUTOINCR);
20455678Spl196000 }
20465678Spl196000
20475678Spl196000 /*
204811348SZhongyan.Gu@Sun.COM * Handle completed sync fib command
204911348SZhongyan.Gu@Sun.COM */
205011348SZhongyan.Gu@Sun.COM /*ARGSUSED*/
205111348SZhongyan.Gu@Sun.COM void
aac_sync_complete(struct aac_softstate * softs,struct aac_cmd * acp)205211348SZhongyan.Gu@Sun.COM aac_sync_complete(struct aac_softstate *softs, struct aac_cmd *acp)
205311348SZhongyan.Gu@Sun.COM {
205411348SZhongyan.Gu@Sun.COM }
205511348SZhongyan.Gu@Sun.COM
205611348SZhongyan.Gu@Sun.COM /*
20575678Spl196000 * Handle completed Flush command
20585678Spl196000 */
20595678Spl196000 /*ARGSUSED*/
20605678Spl196000 static void
aac_synccache_complete(struct aac_softstate * softs,struct aac_cmd * acp)20615678Spl196000 aac_synccache_complete(struct aac_softstate *softs, struct aac_cmd *acp)
20625678Spl196000 {
20635678Spl196000 struct aac_slot *slotp = acp->slotp;
20645678Spl196000 ddi_acc_handle_t acc = slotp->fib_acc_handle;
20655678Spl196000 struct aac_synchronize_reply *resp;
20665678Spl196000 uint32_t status;
20675678Spl196000
20685678Spl196000 ASSERT(!(acp->flags & AAC_CMD_SYNC));
20695678Spl196000
20707567SXin.Chen@Sun.COM acp->pkt->pkt_state |= STATE_GOT_STATUS;
20717567SXin.Chen@Sun.COM
20725678Spl196000 resp = (struct aac_synchronize_reply *)&slotp->fibp->data[0];
20735678Spl196000 status = ddi_get32(acc, &resp->Status);
20745678Spl196000 if (status != CT_OK)
20755678Spl196000 aac_set_arq_data_hwerr(acp);
20765678Spl196000 }
20775678Spl196000
207811636SXin.Chen@Sun.COM /*ARGSUSED*/
207910976SZhongyan.Gu@Sun.COM static void
aac_startstop_complete(struct aac_softstate * softs,struct aac_cmd * acp)208010976SZhongyan.Gu@Sun.COM aac_startstop_complete(struct aac_softstate *softs, struct aac_cmd *acp)
208110976SZhongyan.Gu@Sun.COM {
208210976SZhongyan.Gu@Sun.COM struct aac_slot *slotp = acp->slotp;
208310976SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = slotp->fib_acc_handle;
208410976SZhongyan.Gu@Sun.COM struct aac_Container_resp *resp;
208510976SZhongyan.Gu@Sun.COM uint32_t status;
208610976SZhongyan.Gu@Sun.COM
208710976SZhongyan.Gu@Sun.COM ASSERT(!(acp->flags & AAC_CMD_SYNC));
208810976SZhongyan.Gu@Sun.COM
208910976SZhongyan.Gu@Sun.COM acp->pkt->pkt_state |= STATE_GOT_STATUS;
209010976SZhongyan.Gu@Sun.COM
209110976SZhongyan.Gu@Sun.COM resp = (struct aac_Container_resp *)&slotp->fibp->data[0];
209210976SZhongyan.Gu@Sun.COM status = ddi_get32(acc, &resp->Status);
209310976SZhongyan.Gu@Sun.COM if (status != 0) {
209410976SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN, "Cannot start/stop a unit");
209510976SZhongyan.Gu@Sun.COM aac_set_arq_data_hwerr(acp);
209610976SZhongyan.Gu@Sun.COM }
209710976SZhongyan.Gu@Sun.COM }
209810976SZhongyan.Gu@Sun.COM
20995678Spl196000 /*
21005678Spl196000 * Access PCI space to see if the driver can support the card
21015678Spl196000 */
21025678Spl196000 static int
aac_check_card_type(struct aac_softstate * softs)21035678Spl196000 aac_check_card_type(struct aac_softstate *softs)
21045678Spl196000 {
21055678Spl196000 ddi_acc_handle_t pci_config_handle;
21065678Spl196000 int card_index;
21075678Spl196000 uint32_t pci_cmd;
21085678Spl196000
21095678Spl196000 /* Map pci configuration space */
21105678Spl196000 if ((pci_config_setup(softs->devinfo_p, &pci_config_handle)) !=
21115678Spl196000 DDI_SUCCESS) {
21125678Spl196000 AACDB_PRINT(softs, CE_WARN, "Cannot setup pci config space");
21135678Spl196000 return (AACERR);
21145678Spl196000 }
21155678Spl196000
21165678Spl196000 softs->vendid = pci_config_get16(pci_config_handle, PCI_CONF_VENID);
21175678Spl196000 softs->devid = pci_config_get16(pci_config_handle, PCI_CONF_DEVID);
21185678Spl196000 softs->subvendid = pci_config_get16(pci_config_handle,
21195678Spl196000 PCI_CONF_SUBVENID);
21205678Spl196000 softs->subsysid = pci_config_get16(pci_config_handle,
21215678Spl196000 PCI_CONF_SUBSYSID);
21225678Spl196000
21235678Spl196000 card_index = 0;
21245678Spl196000 while (!CARD_IS_UNKNOWN(card_index)) {
21255678Spl196000 if ((aac_cards[card_index].vendor == softs->vendid) &&
21265678Spl196000 (aac_cards[card_index].device == softs->devid) &&
21275678Spl196000 (aac_cards[card_index].subvendor == softs->subvendid) &&
21285678Spl196000 (aac_cards[card_index].subsys == softs->subsysid)) {
21295678Spl196000 break;
21305678Spl196000 }
21315678Spl196000 card_index++;
21325678Spl196000 }
21335678Spl196000
21345678Spl196000 softs->card = card_index;
21355678Spl196000 softs->hwif = aac_cards[card_index].hwif;
21365678Spl196000
21375678Spl196000 /*
21385678Spl196000 * Unknown aac card
21395678Spl196000 * do a generic match based on the VendorID and DeviceID to
21405678Spl196000 * support the new cards in the aac family
21415678Spl196000 */
21425678Spl196000 if (CARD_IS_UNKNOWN(card_index)) {
21435678Spl196000 if (softs->vendid != 0x9005) {
21445678Spl196000 AACDB_PRINT(softs, CE_WARN,
21455678Spl196000 "Unknown vendor 0x%x", softs->vendid);
21465678Spl196000 goto error;
21475678Spl196000 }
21485678Spl196000 switch (softs->devid) {
21495678Spl196000 case 0x285:
21505678Spl196000 softs->hwif = AAC_HWIF_I960RX;
21515678Spl196000 break;
21525678Spl196000 case 0x286:
21535678Spl196000 softs->hwif = AAC_HWIF_RKT;
21545678Spl196000 break;
21555678Spl196000 default:
21565678Spl196000 AACDB_PRINT(softs, CE_WARN,
21575678Spl196000 "Unknown device \"pci9005,%x\"", softs->devid);
21585678Spl196000 goto error;
21595678Spl196000 }
21605678Spl196000 }
21615678Spl196000
21625678Spl196000 /* Set hardware dependent interface */
21635678Spl196000 switch (softs->hwif) {
21645678Spl196000 case AAC_HWIF_I960RX:
21655678Spl196000 softs->aac_if = aac_rx_interface;
21665678Spl196000 softs->map_size_min = AAC_MAP_SIZE_MIN_RX;
21675678Spl196000 break;
21685678Spl196000 case AAC_HWIF_RKT:
21695678Spl196000 softs->aac_if = aac_rkt_interface;
21705678Spl196000 softs->map_size_min = AAC_MAP_SIZE_MIN_RKT;
21715678Spl196000 break;
21725678Spl196000 default:
21735678Spl196000 AACDB_PRINT(softs, CE_WARN,
21745678Spl196000 "Unknown hardware interface %d", softs->hwif);
21755678Spl196000 goto error;
21765678Spl196000 }
21775678Spl196000
21785678Spl196000 /* Set card names */
21795678Spl196000 (void *)strncpy(softs->vendor_name, aac_cards[card_index].vid,
21805678Spl196000 AAC_VENDOR_LEN);
21815678Spl196000 (void *)strncpy(softs->product_name, aac_cards[card_index].desc,
21825678Spl196000 AAC_PRODUCT_LEN);
21835678Spl196000
21845678Spl196000 /* Set up quirks */
21855678Spl196000 softs->flags = aac_cards[card_index].quirks;
21865678Spl196000
21875678Spl196000 /* Force the busmaster enable bit on */
21885678Spl196000 pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
21895678Spl196000 if ((pci_cmd & PCI_COMM_ME) == 0) {
21905678Spl196000 pci_cmd |= PCI_COMM_ME;
21915678Spl196000 pci_config_put16(pci_config_handle, PCI_CONF_COMM, pci_cmd);
21925678Spl196000 pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
21935678Spl196000 if ((pci_cmd & PCI_COMM_ME) == 0) {
21945678Spl196000 cmn_err(CE_CONT, "?Cannot enable busmaster bit");
21955678Spl196000 goto error;
21965678Spl196000 }
21975678Spl196000 }
21985678Spl196000
21995678Spl196000 /* Set memory base to map */
22005678Spl196000 softs->pci_mem_base_paddr = 0xfffffff0UL & \
22015678Spl196000 pci_config_get32(pci_config_handle, PCI_CONF_BASE0);
22025678Spl196000
22035678Spl196000 pci_config_teardown(&pci_config_handle);
22045678Spl196000
22055678Spl196000 return (AACOK); /* card type detected */
22065678Spl196000 error:
22075678Spl196000 pci_config_teardown(&pci_config_handle);
22085678Spl196000 return (AACERR); /* no matched card found */
22095678Spl196000 }
22105678Spl196000
22115678Spl196000 /*
221211348SZhongyan.Gu@Sun.COM * Do the usual interrupt handler setup stuff.
221311348SZhongyan.Gu@Sun.COM */
221411348SZhongyan.Gu@Sun.COM static int
aac_register_intrs(struct aac_softstate * softs)221511348SZhongyan.Gu@Sun.COM aac_register_intrs(struct aac_softstate *softs)
221611348SZhongyan.Gu@Sun.COM {
221711348SZhongyan.Gu@Sun.COM dev_info_t *dip;
221811348SZhongyan.Gu@Sun.COM int intr_types;
221911348SZhongyan.Gu@Sun.COM
222011348SZhongyan.Gu@Sun.COM ASSERT(softs->devinfo_p);
222111348SZhongyan.Gu@Sun.COM dip = softs->devinfo_p;
222211348SZhongyan.Gu@Sun.COM
222311348SZhongyan.Gu@Sun.COM /* Get the type of device intrrupts */
222411348SZhongyan.Gu@Sun.COM if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
222511348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN,
222611348SZhongyan.Gu@Sun.COM "ddi_intr_get_supported_types() failed");
222711348SZhongyan.Gu@Sun.COM return (AACERR);
222811348SZhongyan.Gu@Sun.COM }
222911348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE,
223011348SZhongyan.Gu@Sun.COM "ddi_intr_get_supported_types() ret: 0x%x", intr_types);
223111348SZhongyan.Gu@Sun.COM
223211348SZhongyan.Gu@Sun.COM /* Query interrupt, and alloc/init all needed struct */
223311348SZhongyan.Gu@Sun.COM if (intr_types & DDI_INTR_TYPE_MSI) {
223411348SZhongyan.Gu@Sun.COM if (aac_query_intrs(softs, DDI_INTR_TYPE_MSI)
223511348SZhongyan.Gu@Sun.COM != DDI_SUCCESS) {
223611348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN,
223711348SZhongyan.Gu@Sun.COM "MSI interrupt query failed");
223811348SZhongyan.Gu@Sun.COM return (AACERR);
223911348SZhongyan.Gu@Sun.COM }
224011348SZhongyan.Gu@Sun.COM softs->intr_type = DDI_INTR_TYPE_MSI;
224111348SZhongyan.Gu@Sun.COM } else if (intr_types & DDI_INTR_TYPE_FIXED) {
224211348SZhongyan.Gu@Sun.COM if (aac_query_intrs(softs, DDI_INTR_TYPE_FIXED)
224311348SZhongyan.Gu@Sun.COM != DDI_SUCCESS) {
224411348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN,
224511348SZhongyan.Gu@Sun.COM "FIXED interrupt query failed");
224611348SZhongyan.Gu@Sun.COM return (AACERR);
224711348SZhongyan.Gu@Sun.COM }
224811348SZhongyan.Gu@Sun.COM softs->intr_type = DDI_INTR_TYPE_FIXED;
224911348SZhongyan.Gu@Sun.COM } else {
225011348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN,
225111348SZhongyan.Gu@Sun.COM "Device cannot suppport both FIXED and MSI interrupts");
225211348SZhongyan.Gu@Sun.COM return (AACERR);
225311348SZhongyan.Gu@Sun.COM }
225411348SZhongyan.Gu@Sun.COM
225511348SZhongyan.Gu@Sun.COM /* Connect interrupt handlers */
225611348SZhongyan.Gu@Sun.COM if (aac_add_intrs(softs) != DDI_SUCCESS) {
225711348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN,
225811348SZhongyan.Gu@Sun.COM "Interrupt registration failed, intr type: %s",
225911348SZhongyan.Gu@Sun.COM softs->intr_type == DDI_INTR_TYPE_MSI ? "MSI" : "FIXED");
226011348SZhongyan.Gu@Sun.COM return (AACERR);
226111348SZhongyan.Gu@Sun.COM }
226211348SZhongyan.Gu@Sun.COM (void) aac_enable_intrs(softs);
226311348SZhongyan.Gu@Sun.COM
226411348SZhongyan.Gu@Sun.COM if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softs->softint_id,
226511348SZhongyan.Gu@Sun.COM NULL, NULL, aac_softintr, (caddr_t)softs) != DDI_SUCCESS) {
226611348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_WARN,
226711348SZhongyan.Gu@Sun.COM "Can not setup soft interrupt handler!");
226811348SZhongyan.Gu@Sun.COM aac_remove_intrs(softs);
226911348SZhongyan.Gu@Sun.COM return (AACERR);
227011348SZhongyan.Gu@Sun.COM }
227111348SZhongyan.Gu@Sun.COM
227211348SZhongyan.Gu@Sun.COM return (AACOK);
227311348SZhongyan.Gu@Sun.COM }
227411348SZhongyan.Gu@Sun.COM
227511348SZhongyan.Gu@Sun.COM static void
aac_unregister_intrs(struct aac_softstate * softs)227611348SZhongyan.Gu@Sun.COM aac_unregister_intrs(struct aac_softstate *softs)
227711348SZhongyan.Gu@Sun.COM {
227811348SZhongyan.Gu@Sun.COM aac_remove_intrs(softs);
227911348SZhongyan.Gu@Sun.COM ddi_remove_softintr(softs->softint_id);
228011348SZhongyan.Gu@Sun.COM }
228111348SZhongyan.Gu@Sun.COM
228211348SZhongyan.Gu@Sun.COM /*
22835678Spl196000 * Check the firmware to determine the features to support and the FIB
22845678Spl196000 * parameters to use.
22855678Spl196000 */
22865678Spl196000 static int
aac_check_firmware(struct aac_softstate * softs)22875678Spl196000 aac_check_firmware(struct aac_softstate *softs)
22885678Spl196000 {
22895678Spl196000 uint32_t options;
22905678Spl196000 uint32_t atu_size;
22915678Spl196000 ddi_acc_handle_t pci_handle;
22927567SXin.Chen@Sun.COM uint8_t *data;
22935678Spl196000 uint32_t max_fibs;
22945678Spl196000 uint32_t max_fib_size;
22955678Spl196000 uint32_t sg_tablesize;
22965678Spl196000 uint32_t max_sectors;
22975678Spl196000 uint32_t status;
22985678Spl196000
22995678Spl196000 /* Get supported options */
23005678Spl196000 if ((aac_sync_mbcommand(softs, AAC_MONKER_GETINFO, 0, 0, 0, 0,
23015678Spl196000 &status)) != AACOK) {
23025678Spl196000 if (status != SRB_STATUS_INVALID_REQUEST) {
23035678Spl196000 cmn_err(CE_CONT,
23045678Spl196000 "?Fatal error: request adapter info error");
23055678Spl196000 return (AACERR);
23065678Spl196000 }
23075678Spl196000 options = 0;
23085678Spl196000 atu_size = 0;
23095678Spl196000 } else {
23105678Spl196000 options = AAC_MAILBOX_GET(softs, 1);
23115678Spl196000 atu_size = AAC_MAILBOX_GET(softs, 2);
23125678Spl196000 }
23135678Spl196000
23145678Spl196000 if (softs->state & AAC_STATE_RESET) {
23155678Spl196000 if ((softs->support_opt == options) &&
23165678Spl196000 (softs->atu_size == atu_size))
23175678Spl196000 return (AACOK);
23185678Spl196000
23195678Spl196000 cmn_err(CE_WARN,
23205678Spl196000 "?Fatal error: firmware changed, system needs reboot");
23215678Spl196000 return (AACERR);
23225678Spl196000 }
23235678Spl196000
23245678Spl196000 /*
23255678Spl196000 * The following critical settings are initialized only once during
23265678Spl196000 * driver attachment.
23275678Spl196000 */
23285678Spl196000 softs->support_opt = options;
23295678Spl196000 softs->atu_size = atu_size;
23305678Spl196000
23315678Spl196000 /* Process supported options */
23325678Spl196000 if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
23335678Spl196000 (softs->flags & AAC_FLAGS_NO4GB) == 0) {
23345678Spl196000 AACDB_PRINT(softs, CE_NOTE, "!Enable FIB map 4GB window");
23355678Spl196000 softs->flags |= AAC_FLAGS_4GB_WINDOW;
23365678Spl196000 } else {
23375678Spl196000 /*
23385678Spl196000 * Quirk AAC_FLAGS_NO4GB is for FIB address and thus comm space
23395678Spl196000 * only. IO is handled by the DMA engine which does not suffer
23405678Spl196000 * from the ATU window programming workarounds necessary for
23415678Spl196000 * CPU copy operations.
23425678Spl196000 */
23435678Spl196000 softs->addr_dma_attr.dma_attr_addr_lo = 0x2000ull;
23445678Spl196000 softs->addr_dma_attr.dma_attr_addr_hi = 0x7fffffffull;
23455678Spl196000 }
23465678Spl196000
23475678Spl196000 if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0) {
23485678Spl196000 AACDB_PRINT(softs, CE_NOTE, "!Enable SG map 64-bit address");
23495678Spl196000 softs->buf_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
23505678Spl196000 softs->buf_dma_attr.dma_attr_seg = 0xffffffffffffffffull;
23515678Spl196000 softs->flags |= AAC_FLAGS_SG_64BIT;
23525678Spl196000 }
23535678Spl196000
23545678Spl196000 if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) {
23555678Spl196000 softs->flags |= AAC_FLAGS_ARRAY_64BIT;
23565678Spl196000 AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array size");
23575678Spl196000 }
23585678Spl196000
23597567SXin.Chen@Sun.COM if (options & AAC_SUPPORTED_NONDASD) {
23607567SXin.Chen@Sun.COM if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p, 0,
23617567SXin.Chen@Sun.COM "nondasd-enable", (char **)&data) == DDI_SUCCESS)) {
23627567SXin.Chen@Sun.COM if (strcmp((char *)data, "yes") == 0) {
23637567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
23647567SXin.Chen@Sun.COM "!Enable Non-DASD access");
23657567SXin.Chen@Sun.COM softs->flags |= AAC_FLAGS_NONDASD;
23667567SXin.Chen@Sun.COM }
23677567SXin.Chen@Sun.COM ddi_prop_free(data);
23687567SXin.Chen@Sun.COM }
23697567SXin.Chen@Sun.COM }
23707567SXin.Chen@Sun.COM
23715678Spl196000 /* Read preferred settings */
23725678Spl196000 max_fib_size = 0;
23735678Spl196000 if ((aac_sync_mbcommand(softs, AAC_MONKER_GETCOMMPREF,
23745678Spl196000 0, 0, 0, 0, NULL)) == AACOK) {
23755678Spl196000 options = AAC_MAILBOX_GET(softs, 1);
23765678Spl196000 max_fib_size = (options & 0xffff);
23775678Spl196000 max_sectors = (options >> 16) << 1;
23785678Spl196000 options = AAC_MAILBOX_GET(softs, 2);
23795678Spl196000 sg_tablesize = (options >> 16);
23805678Spl196000 options = AAC_MAILBOX_GET(softs, 3);
23815678Spl196000 max_fibs = (options & 0xffff);
23825678Spl196000 }
23835678Spl196000
23845678Spl196000 /* Enable new comm. and rawio at the same time */
23855678Spl196000 if ((softs->support_opt & AAC_SUPPORTED_NEW_COMM) &&
23865678Spl196000 (max_fib_size != 0)) {
23877567SXin.Chen@Sun.COM /* read out and save PCI MBR */
23885678Spl196000 if ((atu_size > softs->map_size) &&
23895678Spl196000 (ddi_regs_map_setup(softs->devinfo_p, 1,
239011236SStephen.Hanson@Sun.COM (caddr_t *)&data, 0, atu_size, &softs->reg_attr,
23915678Spl196000 &pci_handle) == DDI_SUCCESS)) {
23925678Spl196000 ddi_regs_map_free(&softs->pci_mem_handle);
23935678Spl196000 softs->pci_mem_handle = pci_handle;
23947567SXin.Chen@Sun.COM softs->pci_mem_base_vaddr = data;
23955678Spl196000 softs->map_size = atu_size;
23965678Spl196000 }
23975678Spl196000 if (atu_size == softs->map_size) {
23985678Spl196000 softs->flags |= AAC_FLAGS_NEW_COMM;
23995678Spl196000 AACDB_PRINT(softs, CE_NOTE,
24005678Spl196000 "!Enable New Comm. interface");
24015678Spl196000 }
24025678Spl196000 }
24035678Spl196000
24045678Spl196000 /* Set FIB parameters */
24055678Spl196000 if (softs->flags & AAC_FLAGS_NEW_COMM) {
24065678Spl196000 softs->aac_max_fibs = max_fibs;
24075678Spl196000 softs->aac_max_fib_size = max_fib_size;
24085678Spl196000 softs->aac_max_sectors = max_sectors;
24095678Spl196000 softs->aac_sg_tablesize = sg_tablesize;
24105678Spl196000
24115678Spl196000 softs->flags |= AAC_FLAGS_RAW_IO;
24125678Spl196000 AACDB_PRINT(softs, CE_NOTE, "!Enable RawIO");
24135678Spl196000 } else {
24145678Spl196000 softs->aac_max_fibs =
24155678Spl196000 (softs->flags & AAC_FLAGS_256FIBS) ? 256 : 512;
24165678Spl196000 softs->aac_max_fib_size = AAC_FIB_SIZE;
24175678Spl196000 softs->aac_max_sectors = 128; /* 64K */
24185678Spl196000 if (softs->flags & AAC_FLAGS_17SG)
24195678Spl196000 softs->aac_sg_tablesize = 17;
24205678Spl196000 else if (softs->flags & AAC_FLAGS_34SG)
24215678Spl196000 softs->aac_sg_tablesize = 34;
24225678Spl196000 else if (softs->flags & AAC_FLAGS_SG_64BIT)
24235678Spl196000 softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
24245678Spl196000 sizeof (struct aac_blockwrite64) +
24255678Spl196000 sizeof (struct aac_sg_entry64)) /
24265678Spl196000 sizeof (struct aac_sg_entry64);
24275678Spl196000 else
24285678Spl196000 softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
24295678Spl196000 sizeof (struct aac_blockwrite) +
24305678Spl196000 sizeof (struct aac_sg_entry)) /
24315678Spl196000 sizeof (struct aac_sg_entry);
24325678Spl196000 }
24335678Spl196000
24345678Spl196000 if ((softs->flags & AAC_FLAGS_RAW_IO) &&
24355678Spl196000 (softs->flags & AAC_FLAGS_ARRAY_64BIT)) {
24365678Spl196000 softs->flags |= AAC_FLAGS_LBA_64BIT;
24375678Spl196000 AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array");
24385678Spl196000 }
24395678Spl196000 softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
24405678Spl196000 softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
24415678Spl196000 /*
24425678Spl196000 * 64K maximum segment size in scatter gather list is controlled by
24435678Spl196000 * the NEW_COMM bit in the adapter information. If not set, the card
24445678Spl196000 * can only accept a maximum of 64K. It is not recommended to permit
24455678Spl196000 * more than 128KB of total transfer size to the adapters because
24465678Spl196000 * performance is negatively impacted.
24475678Spl196000 *
24485678Spl196000 * For new comm, segment size equals max xfer size. For old comm,
24495678Spl196000 * we use 64K for both.
24505678Spl196000 */
24515678Spl196000 softs->buf_dma_attr.dma_attr_count_max =
24525678Spl196000 softs->buf_dma_attr.dma_attr_maxxfer - 1;
24535678Spl196000
24547567SXin.Chen@Sun.COM /* Setup FIB operations */
24555678Spl196000 if (softs->flags & AAC_FLAGS_RAW_IO)
24565678Spl196000 softs->aac_cmd_fib = aac_cmd_fib_rawio;
24575678Spl196000 else if (softs->flags & AAC_FLAGS_SG_64BIT)
24585678Spl196000 softs->aac_cmd_fib = aac_cmd_fib_brw64;
24595678Spl196000 else
24605678Spl196000 softs->aac_cmd_fib = aac_cmd_fib_brw;
24615678Spl196000 softs->aac_cmd_fib_scsi = (softs->flags & AAC_FLAGS_SG_64BIT) ? \
24625678Spl196000 aac_cmd_fib_scsi64 : aac_cmd_fib_scsi32;
24635678Spl196000
24645678Spl196000 /* 64-bit LBA needs descriptor format sense data */
24655678Spl196000 softs->slen = sizeof (struct scsi_arq_status);
24665678Spl196000 if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
24675678Spl196000 softs->slen < AAC_ARQ64_LENGTH)
24685678Spl196000 softs->slen = AAC_ARQ64_LENGTH;
24695678Spl196000
24705678Spl196000 AACDB_PRINT(softs, CE_NOTE,
24715678Spl196000 "!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
24725678Spl196000 softs->aac_max_fibs, softs->aac_max_fib_size,
24735678Spl196000 softs->aac_max_sectors, softs->aac_sg_tablesize);
24745678Spl196000
24755678Spl196000 return (AACOK);
24765678Spl196000 }
24775678Spl196000
24785678Spl196000 static void
aac_fsa_rev(struct aac_softstate * softs,struct FsaRev * fsarev0,struct FsaRev * fsarev1)24795678Spl196000 aac_fsa_rev(struct aac_softstate *softs, struct FsaRev *fsarev0,
24805678Spl196000 struct FsaRev *fsarev1)
24815678Spl196000 {
248211348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
24835678Spl196000
24845678Spl196000 AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.dash);
24855678Spl196000 AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.type);
24865678Spl196000 AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.minor);
24875678Spl196000 AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.major);
24885678Spl196000 AAC_GET_FIELD32(acc, fsarev1, fsarev0, buildNumber);
24895678Spl196000 }
24905678Spl196000
24915678Spl196000 /*
24925678Spl196000 * The following function comes from Adaptec:
24935678Spl196000 *
24945678Spl196000 * Query adapter information and supplement adapter information
24955678Spl196000 */
24965678Spl196000 static int
aac_get_adapter_info(struct aac_softstate * softs,struct aac_adapter_info * ainfr,struct aac_supplement_adapter_info * sinfr)24975678Spl196000 aac_get_adapter_info(struct aac_softstate *softs,
24985678Spl196000 struct aac_adapter_info *ainfr, struct aac_supplement_adapter_info *sinfr)
24995678Spl196000 {
250011348SZhongyan.Gu@Sun.COM struct aac_cmd *acp = &softs->sync_ac;
250111348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
250211348SZhongyan.Gu@Sun.COM struct aac_fib *fibp;
25035678Spl196000 struct aac_adapter_info *ainfp;
25045678Spl196000 struct aac_supplement_adapter_info *sinfp;
250511348SZhongyan.Gu@Sun.COM int rval;
250611348SZhongyan.Gu@Sun.COM
250711348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, acp);
250811348SZhongyan.Gu@Sun.COM acc = acp->slotp->fib_acc_handle;
250911348SZhongyan.Gu@Sun.COM fibp = acp->slotp->fibp;
25105678Spl196000
25115678Spl196000 ddi_put8(acc, &fibp->data[0], 0);
25125678Spl196000 if (aac_sync_fib(softs, RequestAdapterInfo,
2513*12408SZhongyan.Gu@Sun.COM AAC_FIB_SIZEOF(struct aac_adapter_info)) != AACOK) {
25145678Spl196000 AACDB_PRINT(softs, CE_WARN, "RequestAdapterInfo failed");
251511348SZhongyan.Gu@Sun.COM rval = AACERR;
251611348SZhongyan.Gu@Sun.COM goto finish;
25175678Spl196000 }
25185678Spl196000 ainfp = (struct aac_adapter_info *)fibp->data;
25195678Spl196000 if (ainfr) {
25205678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
25215678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, PlatformBase);
25225678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, CpuArchitecture);
25235678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, CpuVariant);
25245678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, ClockSpeed);
25255678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, ExecutionMem);
25265678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, BufferMem);
25275678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, TotalMem);
25285678Spl196000 aac_fsa_rev(softs, &ainfp->KernelRevision,
25295678Spl196000 &ainfr->KernelRevision);
25305678Spl196000 aac_fsa_rev(softs, &ainfp->MonitorRevision,
25315678Spl196000 &ainfr->MonitorRevision);
25325678Spl196000 aac_fsa_rev(softs, &ainfp->HardwareRevision,
25335678Spl196000 &ainfr->HardwareRevision);
25345678Spl196000 aac_fsa_rev(softs, &ainfp->BIOSRevision,
25355678Spl196000 &ainfr->BIOSRevision);
25365678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, ClusteringEnabled);
25375678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, ClusterChannelMask);
25385678Spl196000 AAC_GET_FIELD64(acc, ainfr, ainfp, SerialNumber);
25395678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, batteryPlatform);
25405678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
25415678Spl196000 AAC_GET_FIELD32(acc, ainfr, ainfp, OemVariant);
25425678Spl196000 }
25435678Spl196000 if (sinfr) {
25445678Spl196000 if (!(softs->support_opt &
25455678Spl196000 AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO)) {
25465678Spl196000 AACDB_PRINT(softs, CE_WARN,
25475678Spl196000 "SupplementAdapterInfo not supported");
254811348SZhongyan.Gu@Sun.COM rval = AACERR;
254911348SZhongyan.Gu@Sun.COM goto finish;
25505678Spl196000 }
25515678Spl196000 ddi_put8(acc, &fibp->data[0], 0);
25525678Spl196000 if (aac_sync_fib(softs, RequestSupplementAdapterInfo,
2553*12408SZhongyan.Gu@Sun.COM AAC_FIB_SIZEOF(struct aac_supplement_adapter_info))
2554*12408SZhongyan.Gu@Sun.COM != AACOK) {
25555678Spl196000 AACDB_PRINT(softs, CE_WARN,
25565678Spl196000 "RequestSupplementAdapterInfo failed");
255711348SZhongyan.Gu@Sun.COM rval = AACERR;
255811348SZhongyan.Gu@Sun.COM goto finish;
25595678Spl196000 }
25605678Spl196000 sinfp = (struct aac_supplement_adapter_info *)fibp->data;
25615678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, AdapterTypeText[0], 17+1);
25625678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, Pad[0], 2);
25635678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, FlashMemoryByteSize);
25645678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, FlashImageId);
25655678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, MaxNumberPorts);
25665678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, Version);
25675678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits);
25685678Spl196000 AAC_GET_FIELD8(acc, sinfr, sinfp, SlotNumber);
25695678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, ReservedPad0[0], 3);
25705678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, BuildDate[0], 12);
25715678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, CurrentNumberPorts);
25725678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, VpdInfo,
25735678Spl196000 sizeof (struct vpd_info));
25745678Spl196000 aac_fsa_rev(softs, &sinfp->FlashFirmwareRevision,
25755678Spl196000 &sinfr->FlashFirmwareRevision);
25765678Spl196000 AAC_GET_FIELD32(acc, sinfr, sinfp, RaidTypeMorphOptions);
25775678Spl196000 aac_fsa_rev(softs, &sinfp->FlashFirmwareBootRevision,
25785678Spl196000 &sinfr->FlashFirmwareBootRevision);
25795678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgPcbaSerialNo,
25805678Spl196000 MFG_PCBA_SERIAL_NUMBER_WIDTH);
25815678Spl196000 AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgWWNName[0],
25825678Spl196000 MFG_WWN_WIDTH);
258310976SZhongyan.Gu@Sun.COM AAC_GET_FIELD32(acc, sinfr, sinfp, SupportedOptions2);
258410976SZhongyan.Gu@Sun.COM AAC_GET_FIELD32(acc, sinfr, sinfp, ExpansionFlag);
258510976SZhongyan.Gu@Sun.COM if (sinfr->ExpansionFlag == 1) {
258610976SZhongyan.Gu@Sun.COM AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits3);
258710976SZhongyan.Gu@Sun.COM AAC_GET_FIELD32(acc, sinfr, sinfp,
258810976SZhongyan.Gu@Sun.COM SupportedPerformanceMode);
258910976SZhongyan.Gu@Sun.COM AAC_REP_GET_FIELD32(acc, sinfr, sinfp,
259010976SZhongyan.Gu@Sun.COM ReservedGrowth[0], 80);
259110976SZhongyan.Gu@Sun.COM }
25925678Spl196000 }
259311348SZhongyan.Gu@Sun.COM rval = AACOK;
259411348SZhongyan.Gu@Sun.COM finish:
259511348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, acp);
259611348SZhongyan.Gu@Sun.COM return (rval);
25975678Spl196000 }
25985678Spl196000
25997567SXin.Chen@Sun.COM static int
aac_get_bus_info(struct aac_softstate * softs,uint32_t * bus_max,uint32_t * tgt_max)26007567SXin.Chen@Sun.COM aac_get_bus_info(struct aac_softstate *softs, uint32_t *bus_max,
26017567SXin.Chen@Sun.COM uint32_t *tgt_max)
26027567SXin.Chen@Sun.COM {
260311348SZhongyan.Gu@Sun.COM struct aac_cmd *acp = &softs->sync_ac;
260411348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
260511348SZhongyan.Gu@Sun.COM struct aac_fib *fibp;
26067567SXin.Chen@Sun.COM struct aac_ctcfg *c_cmd;
26077567SXin.Chen@Sun.COM struct aac_ctcfg_resp *c_resp;
26087567SXin.Chen@Sun.COM uint32_t scsi_method_id;
26097567SXin.Chen@Sun.COM struct aac_bus_info *cmd;
26107567SXin.Chen@Sun.COM struct aac_bus_info_response *resp;
26117567SXin.Chen@Sun.COM int rval;
26127567SXin.Chen@Sun.COM
261311348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, acp);
261411348SZhongyan.Gu@Sun.COM acc = acp->slotp->fib_acc_handle;
261511348SZhongyan.Gu@Sun.COM fibp = acp->slotp->fibp;
261611348SZhongyan.Gu@Sun.COM
26177567SXin.Chen@Sun.COM /* Detect MethodId */
26187567SXin.Chen@Sun.COM c_cmd = (struct aac_ctcfg *)&fibp->data[0];
26197567SXin.Chen@Sun.COM ddi_put32(acc, &c_cmd->Command, VM_ContainerConfig);
26207567SXin.Chen@Sun.COM ddi_put32(acc, &c_cmd->cmd, CT_GET_SCSI_METHOD);
26217567SXin.Chen@Sun.COM ddi_put32(acc, &c_cmd->param, 0);
26227567SXin.Chen@Sun.COM rval = aac_sync_fib(softs, ContainerCommand,
26237567SXin.Chen@Sun.COM AAC_FIB_SIZEOF(struct aac_ctcfg));
26247567SXin.Chen@Sun.COM c_resp = (struct aac_ctcfg_resp *)&fibp->data[0];
26257567SXin.Chen@Sun.COM if (rval != AACOK || ddi_get32(acc, &c_resp->Status) != 0) {
26267567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN,
26277567SXin.Chen@Sun.COM "VM_ContainerConfig command fail");
262811348SZhongyan.Gu@Sun.COM rval = AACERR;
262911348SZhongyan.Gu@Sun.COM goto finish;
26307567SXin.Chen@Sun.COM }
26317567SXin.Chen@Sun.COM scsi_method_id = ddi_get32(acc, &c_resp->param);
26327567SXin.Chen@Sun.COM
26337567SXin.Chen@Sun.COM /* Detect phys. bus count and max. target id first */
26347567SXin.Chen@Sun.COM cmd = (struct aac_bus_info *)&fibp->data[0];
26357567SXin.Chen@Sun.COM ddi_put32(acc, &cmd->Command, VM_Ioctl);
26367567SXin.Chen@Sun.COM ddi_put32(acc, &cmd->ObjType, FT_DRIVE); /* physical drive */
26377567SXin.Chen@Sun.COM ddi_put32(acc, &cmd->MethodId, scsi_method_id);
26387567SXin.Chen@Sun.COM ddi_put32(acc, &cmd->ObjectId, 0);
26397567SXin.Chen@Sun.COM ddi_put32(acc, &cmd->CtlCmd, GetBusInfo);
26407567SXin.Chen@Sun.COM /*
26417567SXin.Chen@Sun.COM * For VM_Ioctl, the firmware uses the Header.Size filled from the
26427567SXin.Chen@Sun.COM * driver as the size to be returned. Therefore the driver has to use
26437567SXin.Chen@Sun.COM * sizeof (struct aac_bus_info_response) because it is greater than
26447567SXin.Chen@Sun.COM * sizeof (struct aac_bus_info).
26457567SXin.Chen@Sun.COM */
26467567SXin.Chen@Sun.COM rval = aac_sync_fib(softs, ContainerCommand,
26477567SXin.Chen@Sun.COM AAC_FIB_SIZEOF(struct aac_bus_info_response));
26487567SXin.Chen@Sun.COM resp = (struct aac_bus_info_response *)cmd;
26497567SXin.Chen@Sun.COM
26507567SXin.Chen@Sun.COM /* Scan all coordinates with INQUIRY */
26517567SXin.Chen@Sun.COM if ((rval != AACOK) || (ddi_get32(acc, &resp->Status) != 0)) {
26527567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "GetBusInfo command fail");
265311348SZhongyan.Gu@Sun.COM rval = AACERR;
265411348SZhongyan.Gu@Sun.COM goto finish;
26557567SXin.Chen@Sun.COM }
26567567SXin.Chen@Sun.COM *bus_max = ddi_get32(acc, &resp->BusCount);
26577567SXin.Chen@Sun.COM *tgt_max = ddi_get32(acc, &resp->TargetsPerBus);
265811348SZhongyan.Gu@Sun.COM
265911348SZhongyan.Gu@Sun.COM finish:
266011348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, acp);
26617567SXin.Chen@Sun.COM return (AACOK);
26627567SXin.Chen@Sun.COM }
26637567SXin.Chen@Sun.COM
26645678Spl196000 /*
26655678Spl196000 * The following function comes from Adaptec:
26665678Spl196000 *
26675678Spl196000 * Routine to be called during initialization of communications with
26685678Spl196000 * the adapter to handle possible adapter configuration issues. When
26695678Spl196000 * the adapter first boots up, it examines attached drives, etc, and
26705678Spl196000 * potentially comes up with a new or revised configuration (relative to
26715678Spl196000 * what's stored in it's NVRAM). Additionally it may discover problems
26725678Spl196000 * that make the current physical configuration unworkable (currently
26735678Spl196000 * applicable only to cluster configuration issues).
26745678Spl196000 *
26755678Spl196000 * If there are no configuration issues or the issues are considered
26765678Spl196000 * trival by the adapter, it will set it's configuration status to
26775678Spl196000 * "FSACT_CONTINUE" and execute the "commit confiuguration" action
26785678Spl196000 * automatically on it's own.
26795678Spl196000 *
26805678Spl196000 * However, if there are non-trivial issues, the adapter will set it's
26815678Spl196000 * internal configuration status to "FSACT_PAUSE" or "FASCT_ABORT"
26825678Spl196000 * and wait for some agent on the host to issue the "\ContainerCommand
26835678Spl196000 * \VM_ContainerConfig\CT_COMMIT_CONFIG" FIB command to cause the
26845678Spl196000 * adapter to commit the new/updated configuration and enable
26855678Spl196000 * un-inhibited operation. The host agent should first issue the
26865678Spl196000 * "\ContainerCommand\VM_ContainerConfig\CT_GET_CONFIG_STATUS" FIB
26875678Spl196000 * command to obtain information about config issues detected by
26885678Spl196000 * the adapter.
26895678Spl196000 *
26905678Spl196000 * Normally the adapter's PC BIOS will execute on the host following
26915678Spl196000 * adapter poweron and reset and will be responsible for querring the
26925678Spl196000 * adapter with CT_GET_CONFIG_STATUS and issuing the CT_COMMIT_CONFIG
26935678Spl196000 * command if appropriate.
26945678Spl196000 *
26955678Spl196000 * However, with the introduction of IOP reset support, the adapter may
26965678Spl196000 * boot up without the benefit of the adapter's PC BIOS host agent.
26975678Spl196000 * This routine is intended to take care of these issues in situations
26985678Spl196000 * where BIOS doesn't execute following adapter poweron or reset. The
26995678Spl196000 * CT_COMMIT_CONFIG command is a no-op if it's already been issued, so
27005678Spl196000 * there is no harm in doing this when it's already been done.
27015678Spl196000 */
27025678Spl196000 static int
aac_handle_adapter_config_issues(struct aac_softstate * softs)27035678Spl196000 aac_handle_adapter_config_issues(struct aac_softstate *softs)
27045678Spl196000 {
270511348SZhongyan.Gu@Sun.COM struct aac_cmd *acp = &softs->sync_ac;
270611348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
270711348SZhongyan.Gu@Sun.COM struct aac_fib *fibp;
27085678Spl196000 struct aac_Container *cmd;
27095678Spl196000 struct aac_Container_resp *resp;
27105678Spl196000 struct aac_cf_status_header *cfg_sts_hdr;
27115678Spl196000 uint32_t resp_status;
27125678Spl196000 uint32_t ct_status;
27135678Spl196000 uint32_t cfg_stat_action;
27145678Spl196000 int rval;
27155678Spl196000
271611348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, acp);
271711348SZhongyan.Gu@Sun.COM acc = acp->slotp->fib_acc_handle;
271811348SZhongyan.Gu@Sun.COM fibp = acp->slotp->fibp;
271911348SZhongyan.Gu@Sun.COM
27205678Spl196000 /* Get adapter config status */
27215678Spl196000 cmd = (struct aac_Container *)&fibp->data[0];
27225678Spl196000
27235678Spl196000 bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
27245678Spl196000 ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
27255678Spl196000 ddi_put32(acc, &cmd->CTCommand.command, CT_GET_CONFIG_STATUS);
27265678Spl196000 ddi_put32(acc, &cmd->CTCommand.param[CNT_SIZE],
27275678Spl196000 sizeof (struct aac_cf_status_header));
27285678Spl196000 rval = aac_sync_fib(softs, ContainerCommand,
27295678Spl196000 AAC_FIB_SIZEOF(struct aac_Container));
27305678Spl196000 resp = (struct aac_Container_resp *)cmd;
27315678Spl196000 cfg_sts_hdr = (struct aac_cf_status_header *)resp->CTResponse.data;
27325678Spl196000
27335678Spl196000 resp_status = ddi_get32(acc, &resp->Status);
27345678Spl196000 ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
27355678Spl196000 if ((rval == AACOK) && (resp_status == 0) && (ct_status == CT_OK)) {
27365678Spl196000 cfg_stat_action = ddi_get32(acc, &cfg_sts_hdr->action);
27375678Spl196000
27385678Spl196000 /* Commit configuration if it's reasonable to do so. */
27395678Spl196000 if (cfg_stat_action <= CFACT_PAUSE) {
27405678Spl196000 bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
27415678Spl196000 ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
27425678Spl196000 ddi_put32(acc, &cmd->CTCommand.command,
27435678Spl196000 CT_COMMIT_CONFIG);
27445678Spl196000 rval = aac_sync_fib(softs, ContainerCommand,
27455678Spl196000 AAC_FIB_SIZEOF(struct aac_Container));
27465678Spl196000
27475678Spl196000 resp_status = ddi_get32(acc, &resp->Status);
27485678Spl196000 ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
27495678Spl196000 if ((rval == AACOK) && (resp_status == 0) &&
27505678Spl196000 (ct_status == CT_OK))
27515678Spl196000 /* Successful completion */
27525678Spl196000 rval = AACMPE_OK;
27535678Spl196000 else
27545678Spl196000 /* Auto-commit aborted due to error(s). */
27555678Spl196000 rval = AACMPE_COMMIT_CONFIG;
27565678Spl196000 } else {
27575678Spl196000 /*
27585678Spl196000 * Auto-commit aborted due to adapter indicating
27595678Spl196000 * configuration issue(s) too dangerous to auto-commit.
27605678Spl196000 */
27615678Spl196000 rval = AACMPE_CONFIG_STATUS;
27625678Spl196000 }
27635678Spl196000 } else {
27645678Spl196000 cmn_err(CE_WARN, "!Configuration issue, auto-commit aborted");
27655678Spl196000 rval = AACMPE_CONFIG_STATUS;
27665678Spl196000 }
276711348SZhongyan.Gu@Sun.COM
276811348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, acp);
27695678Spl196000 return (rval);
27705678Spl196000 }
27715678Spl196000
27725678Spl196000 /*
27735678Spl196000 * Hardware initialization and resource allocation
27745678Spl196000 */
27755678Spl196000 static int
aac_common_attach(struct aac_softstate * softs)27765678Spl196000 aac_common_attach(struct aac_softstate *softs)
27775678Spl196000 {
27785678Spl196000 uint32_t status;
27795678Spl196000 int i;
278011964SXin.Chen@Sun.COM struct aac_supplement_adapter_info sinf;
27815678Spl196000
27825678Spl196000 DBCALLED(softs, 1);
27835678Spl196000
27845678Spl196000 /*
27855678Spl196000 * Do a little check here to make sure there aren't any outstanding
27865678Spl196000 * FIBs in the message queue. At this point there should not be and
27875678Spl196000 * if there are they are probably left over from another instance of
27885678Spl196000 * the driver like when the system crashes and the crash dump driver
27895678Spl196000 * gets loaded.
27905678Spl196000 */
27915678Spl196000 while (AAC_OUTB_GET(softs) != 0xfffffffful)
27925678Spl196000 ;
27935678Spl196000
27945678Spl196000 /*
27955678Spl196000 * Wait the card to complete booting up before do anything that
27965678Spl196000 * attempts to communicate with it.
27975678Spl196000 */
27985678Spl196000 status = AAC_FWSTATUS_GET(softs);
27995678Spl196000 if (status == AAC_SELF_TEST_FAILED || status == AAC_KERNEL_PANIC)
28005678Spl196000 goto error;
28015678Spl196000 i = AAC_FWUP_TIMEOUT * 1000; /* set timeout */
28025678Spl196000 AAC_BUSYWAIT(AAC_FWSTATUS_GET(softs) & AAC_KERNEL_UP_AND_RUNNING, i);
28035678Spl196000 if (i == 0) {
28045678Spl196000 cmn_err(CE_CONT, "?Fatal error: controller not ready");
28055678Spl196000 aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28065678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28075678Spl196000 goto error;
28085678Spl196000 }
28095678Spl196000
28105678Spl196000 /* Read and set card supported options and settings */
28115678Spl196000 if (aac_check_firmware(softs) == AACERR) {
28125678Spl196000 aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28135678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28145678Spl196000 goto error;
28155678Spl196000 }
28165678Spl196000
281711348SZhongyan.Gu@Sun.COM /* Add interrupt handlers */
281811348SZhongyan.Gu@Sun.COM if (aac_register_intrs(softs) == AACERR) {
281911348SZhongyan.Gu@Sun.COM cmn_err(CE_CONT,
282011348SZhongyan.Gu@Sun.COM "?Fatal error: interrupts register failed");
282111348SZhongyan.Gu@Sun.COM goto error;
282211348SZhongyan.Gu@Sun.COM }
28235678Spl196000
28245678Spl196000 /* Setup communication space with the card */
28255678Spl196000 if (softs->comm_space_dma_handle == NULL) {
28265678Spl196000 if (aac_alloc_comm_space(softs) != AACOK)
28275678Spl196000 goto error;
28285678Spl196000 }
28295678Spl196000 if (aac_setup_comm_space(softs) != AACOK) {
28305678Spl196000 cmn_err(CE_CONT, "?Setup communication space failed");
28315678Spl196000 aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28325678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28335678Spl196000 goto error;
28345678Spl196000 }
28355678Spl196000
28365678Spl196000 #ifdef DEBUG
28375678Spl196000 if (aac_get_fw_debug_buffer(softs) != AACOK)
28385678Spl196000 cmn_err(CE_CONT, "?firmware UART trace not supported");
28395678Spl196000 #endif
28405678Spl196000
28415678Spl196000 /* Allocate slots */
28425678Spl196000 if ((softs->total_slots == 0) && (aac_create_slots(softs) != AACOK)) {
28435678Spl196000 cmn_err(CE_CONT, "?Fatal error: slots allocate failed");
28445678Spl196000 goto error;
28455678Spl196000 }
28465678Spl196000 AACDB_PRINT(softs, CE_NOTE, "%d slots allocated", softs->total_slots);
28475678Spl196000
28485678Spl196000 /* Allocate FIBs */
28495678Spl196000 if (softs->total_fibs < softs->total_slots) {
28505678Spl196000 aac_alloc_fibs(softs);
28515678Spl196000 if (softs->total_fibs == 0)
28525678Spl196000 goto error;
28535678Spl196000 AACDB_PRINT(softs, CE_NOTE, "%d fibs allocated",
28545678Spl196000 softs->total_fibs);
28555678Spl196000 }
28565678Spl196000
285711348SZhongyan.Gu@Sun.COM AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
285811348SZhongyan.Gu@Sun.COM AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
285911348SZhongyan.Gu@Sun.COM
286011964SXin.Chen@Sun.COM if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
2861*12408SZhongyan.Gu@Sun.COM softs->feature_bits = sinf.FeatureBits;
2862*12408SZhongyan.Gu@Sun.COM softs->support_opt2 = sinf.SupportedOptions2;
2863*12408SZhongyan.Gu@Sun.COM
286411964SXin.Chen@Sun.COM /* Get adapter names */
286511964SXin.Chen@Sun.COM if (CARD_IS_UNKNOWN(softs->card)) {
28665678Spl196000 char *p, *p0, *p1;
28675678Spl196000
28685678Spl196000 /*
28695678Spl196000 * Now find the controller name in supp_adapter_info->
28705678Spl196000 * AdapterTypeText. Use the first word as the vendor
28715678Spl196000 * and the other words as the product name.
28725678Spl196000 */
28735678Spl196000 AACDB_PRINT(softs, CE_NOTE, "sinf.AdapterTypeText = "
28745678Spl196000 "\"%s\"", sinf.AdapterTypeText);
28755678Spl196000 p = sinf.AdapterTypeText;
28765678Spl196000 p0 = p1 = NULL;
28775678Spl196000 /* Skip heading spaces */
28785678Spl196000 while (*p && (*p == ' ' || *p == '\t'))
28795678Spl196000 p++;
28805678Spl196000 p0 = p;
28815678Spl196000 while (*p && (*p != ' ' && *p != '\t'))
28825678Spl196000 p++;
28835678Spl196000 /* Remove middle spaces */
28845678Spl196000 while (*p && (*p == ' ' || *p == '\t'))
28855678Spl196000 *p++ = 0;
28865678Spl196000 p1 = p;
28875678Spl196000 /* Remove trailing spaces */
28885678Spl196000 p = p1 + strlen(p1) - 1;
28895678Spl196000 while (p > p1 && (*p == ' ' || *p == '\t'))
28905678Spl196000 *p-- = 0;
28915678Spl196000 if (*p0 && *p1) {
28925678Spl196000 (void *)strncpy(softs->vendor_name, p0,
28935678Spl196000 AAC_VENDOR_LEN);
28945678Spl196000 (void *)strncpy(softs->product_name, p1,
28955678Spl196000 AAC_PRODUCT_LEN);
28965678Spl196000 } else {
28975678Spl196000 cmn_err(CE_WARN,
28985678Spl196000 "?adapter name mis-formatted\n");
28995678Spl196000 if (*p0)
29005678Spl196000 (void *)strncpy(softs->product_name,
29015678Spl196000 p0, AAC_PRODUCT_LEN);
29025678Spl196000 }
29035678Spl196000 }
290411964SXin.Chen@Sun.COM } else {
290511964SXin.Chen@Sun.COM cmn_err(CE_CONT, "?Query adapter information failed");
290611964SXin.Chen@Sun.COM }
290711964SXin.Chen@Sun.COM
29085678Spl196000
29095678Spl196000 cmn_err(CE_NOTE,
29105678Spl196000 "!aac driver %d.%02d.%02d-%d, found card: " \
29115678Spl196000 "%s %s(pci0x%x.%x.%x.%x) at 0x%x",
29125678Spl196000 AAC_DRIVER_MAJOR_VERSION,
29135678Spl196000 AAC_DRIVER_MINOR_VERSION,
29145678Spl196000 AAC_DRIVER_BUGFIX_LEVEL,
29155678Spl196000 AAC_DRIVER_BUILD,
29165678Spl196000 softs->vendor_name, softs->product_name,
29175678Spl196000 softs->vendid, softs->devid, softs->subvendid, softs->subsysid,
29185678Spl196000 softs->pci_mem_base_paddr);
29195678Spl196000
29205678Spl196000 /* Perform acceptance of adapter-detected config changes if possible */
29215678Spl196000 if (aac_handle_adapter_config_issues(softs) != AACMPE_OK) {
29225678Spl196000 cmn_err(CE_CONT, "?Handle adapter config issues failed");
29235678Spl196000 aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
29245678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29255678Spl196000 goto error;
29265678Spl196000 }
29275678Spl196000
29287567SXin.Chen@Sun.COM /* Setup containers (logical devices) */
29295678Spl196000 if (aac_probe_containers(softs) != AACOK) {
29305678Spl196000 cmn_err(CE_CONT, "?Fatal error: get container info error");
29315678Spl196000 goto error;
29325678Spl196000 }
29335678Spl196000
2934*12408SZhongyan.Gu@Sun.COM /* Check for JBOD support. Default disable */
2935*12408SZhongyan.Gu@Sun.COM char *data;
2936*12408SZhongyan.Gu@Sun.COM if (softs->feature_bits & AAC_FEATURE_SUPPORTED_JBOD) {
2937*12408SZhongyan.Gu@Sun.COM if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p,
2938*12408SZhongyan.Gu@Sun.COM 0, "jbod-enable", &data) == DDI_SUCCESS)) {
2939*12408SZhongyan.Gu@Sun.COM if (strcmp(data, "yes") == 0) {
2940*12408SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE,
2941*12408SZhongyan.Gu@Sun.COM "Enable JBOD access");
2942*12408SZhongyan.Gu@Sun.COM softs->flags |= AAC_FLAGS_JBOD;
2943*12408SZhongyan.Gu@Sun.COM }
2944*12408SZhongyan.Gu@Sun.COM ddi_prop_free(data);
2945*12408SZhongyan.Gu@Sun.COM }
2946*12408SZhongyan.Gu@Sun.COM }
2947*12408SZhongyan.Gu@Sun.COM
29487567SXin.Chen@Sun.COM /* Setup phys. devices */
2949*12408SZhongyan.Gu@Sun.COM if (softs->flags & (AAC_FLAGS_NONDASD | AAC_FLAGS_JBOD)) {
29507567SXin.Chen@Sun.COM uint32_t bus_max, tgt_max;
29517567SXin.Chen@Sun.COM uint32_t bus, tgt;
29527567SXin.Chen@Sun.COM int index;
29537567SXin.Chen@Sun.COM
29547567SXin.Chen@Sun.COM if (aac_get_bus_info(softs, &bus_max, &tgt_max) != AACOK) {
29557567SXin.Chen@Sun.COM cmn_err(CE_CONT, "?Fatal error: get bus info error");
29567567SXin.Chen@Sun.COM goto error;
29577567SXin.Chen@Sun.COM }
29587567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "bus_max=%d, tgt_max=%d",
29597567SXin.Chen@Sun.COM bus_max, tgt_max);
29607567SXin.Chen@Sun.COM if (bus_max != softs->bus_max || tgt_max != softs->tgt_max) {
29617567SXin.Chen@Sun.COM if (softs->state & AAC_STATE_RESET) {
29627567SXin.Chen@Sun.COM cmn_err(CE_WARN,
29637567SXin.Chen@Sun.COM "?Fatal error: bus map changed");
29647567SXin.Chen@Sun.COM goto error;
29657567SXin.Chen@Sun.COM }
29667567SXin.Chen@Sun.COM softs->bus_max = bus_max;
29677567SXin.Chen@Sun.COM softs->tgt_max = tgt_max;
29687567SXin.Chen@Sun.COM if (softs->nondasds) {
29697567SXin.Chen@Sun.COM kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
29707567SXin.Chen@Sun.COM sizeof (struct aac_nondasd));
29717567SXin.Chen@Sun.COM }
29727567SXin.Chen@Sun.COM softs->nondasds = kmem_zalloc(AAC_MAX_PD(softs) * \
29737567SXin.Chen@Sun.COM sizeof (struct aac_nondasd), KM_SLEEP);
29747567SXin.Chen@Sun.COM
29757567SXin.Chen@Sun.COM index = 0;
29767567SXin.Chen@Sun.COM for (bus = 0; bus < softs->bus_max; bus++) {
29777567SXin.Chen@Sun.COM for (tgt = 0; tgt < softs->tgt_max; tgt++) {
29787567SXin.Chen@Sun.COM struct aac_nondasd *dvp =
29797567SXin.Chen@Sun.COM &softs->nondasds[index++];
29807567SXin.Chen@Sun.COM dvp->dev.type = AAC_DEV_PD;
29817567SXin.Chen@Sun.COM dvp->bus = bus;
29827567SXin.Chen@Sun.COM dvp->tid = tgt;
29837567SXin.Chen@Sun.COM }
29847567SXin.Chen@Sun.COM }
29857567SXin.Chen@Sun.COM }
29867567SXin.Chen@Sun.COM }
29877567SXin.Chen@Sun.COM
29885678Spl196000 /* Check dma & acc handles allocated in attach */
29895678Spl196000 if (aac_check_dma_handle(softs->comm_space_dma_handle) != DDI_SUCCESS) {
29905678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29915678Spl196000 goto error;
29925678Spl196000 }
29935678Spl196000
29945678Spl196000 if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
29955678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29965678Spl196000 goto error;
29975678Spl196000 }
29985678Spl196000
29995678Spl196000 for (i = 0; i < softs->total_slots; i++) {
30005678Spl196000 if (aac_check_dma_handle(softs->io_slot[i].fib_dma_handle) !=
30015678Spl196000 DDI_SUCCESS) {
30025678Spl196000 ddi_fm_service_impact(softs->devinfo_p,
30035678Spl196000 DDI_SERVICE_LOST);
30045678Spl196000 goto error;
30055678Spl196000 }
30065678Spl196000 }
30075678Spl196000
30085678Spl196000 return (AACOK);
30095678Spl196000 error:
30105678Spl196000 if (softs->state & AAC_STATE_RESET)
30115678Spl196000 return (AACERR);
30127567SXin.Chen@Sun.COM if (softs->nondasds) {
30137567SXin.Chen@Sun.COM kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
30147567SXin.Chen@Sun.COM sizeof (struct aac_nondasd));
30157567SXin.Chen@Sun.COM softs->nondasds = NULL;
30167567SXin.Chen@Sun.COM }
30175678Spl196000 if (softs->total_fibs > 0)
30185678Spl196000 aac_destroy_fibs(softs);
30195678Spl196000 if (softs->total_slots > 0)
30205678Spl196000 aac_destroy_slots(softs);
30215678Spl196000 if (softs->comm_space_dma_handle)
30225678Spl196000 aac_free_comm_space(softs);
30235678Spl196000 return (AACERR);
30245678Spl196000 }
30255678Spl196000
30265678Spl196000 /*
30275678Spl196000 * Hardware shutdown and resource release
30285678Spl196000 */
30295678Spl196000 static void
aac_common_detach(struct aac_softstate * softs)30305678Spl196000 aac_common_detach(struct aac_softstate *softs)
30315678Spl196000 {
30325678Spl196000 DBCALLED(softs, 1);
30335678Spl196000
303411348SZhongyan.Gu@Sun.COM aac_unregister_intrs(softs);
303511348SZhongyan.Gu@Sun.COM
303611348SZhongyan.Gu@Sun.COM mutex_enter(&softs->io_lock);
30375678Spl196000 (void) aac_shutdown(softs);
30385678Spl196000
30397567SXin.Chen@Sun.COM if (softs->nondasds) {
30407567SXin.Chen@Sun.COM kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
30417567SXin.Chen@Sun.COM sizeof (struct aac_nondasd));
30427567SXin.Chen@Sun.COM softs->nondasds = NULL;
30437567SXin.Chen@Sun.COM }
30445678Spl196000 aac_destroy_fibs(softs);
30455678Spl196000 aac_destroy_slots(softs);
30465678Spl196000 aac_free_comm_space(softs);
304711348SZhongyan.Gu@Sun.COM mutex_exit(&softs->io_lock);
30485678Spl196000 }
30495678Spl196000
30505678Spl196000 /*
30515678Spl196000 * Send a synchronous command to the controller and wait for a result.
30525678Spl196000 * Indicate if the controller completed the command with an error status.
30535678Spl196000 */
30545678Spl196000 int
aac_sync_mbcommand(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,uint32_t * statusp)30555678Spl196000 aac_sync_mbcommand(struct aac_softstate *softs, uint32_t cmd,
30565678Spl196000 uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3,
30575678Spl196000 uint32_t *statusp)
30585678Spl196000 {
30595678Spl196000 int timeout;
30605678Spl196000 uint32_t status;
30615678Spl196000
30625678Spl196000 if (statusp != NULL)
30635678Spl196000 *statusp = SRB_STATUS_SUCCESS;
30645678Spl196000
30655678Spl196000 /* Fill in mailbox */
30665678Spl196000 AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3);
30675678Spl196000
30685678Spl196000 /* Ensure the sync command doorbell flag is cleared */
30695678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
30705678Spl196000
30715678Spl196000 /* Then set it to signal the adapter */
30725678Spl196000 AAC_NOTIFY(softs, AAC_DB_SYNC_COMMAND);
30735678Spl196000
30745678Spl196000 /* Spin waiting for the command to complete */
30755678Spl196000 timeout = AAC_IMMEDIATE_TIMEOUT * 1000;
30765678Spl196000 AAC_BUSYWAIT(AAC_STATUS_GET(softs) & AAC_DB_SYNC_COMMAND, timeout);
30775678Spl196000 if (!timeout) {
30785678Spl196000 AACDB_PRINT(softs, CE_WARN,
30795678Spl196000 "Sync command timed out after %d seconds (0x%x)!",
30805678Spl196000 AAC_IMMEDIATE_TIMEOUT, AAC_FWSTATUS_GET(softs));
30815678Spl196000 return (AACERR);
30825678Spl196000 }
30835678Spl196000
30845678Spl196000 /* Clear the completion flag */
30855678Spl196000 AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
30865678Spl196000
30875678Spl196000 /* Get the command status */
30885678Spl196000 status = AAC_MAILBOX_GET(softs, 0);
30895678Spl196000 if (statusp != NULL)
30905678Spl196000 *statusp = status;
30915678Spl196000 if (status != SRB_STATUS_SUCCESS) {
30925678Spl196000 AACDB_PRINT(softs, CE_WARN,
30935678Spl196000 "Sync command fail: status = 0x%x", status);
30945678Spl196000 return (AACERR);
30955678Spl196000 }
30965678Spl196000
30975678Spl196000 return (AACOK);
30985678Spl196000 }
30995678Spl196000
31005678Spl196000 /*
31015678Spl196000 * Send a synchronous FIB to the adapter and wait for its completion
31025678Spl196000 */
31035678Spl196000 static int
aac_sync_fib(struct aac_softstate * softs,uint16_t cmd,uint16_t fibsize)31045678Spl196000 aac_sync_fib(struct aac_softstate *softs, uint16_t cmd, uint16_t fibsize)
31055678Spl196000 {
310611348SZhongyan.Gu@Sun.COM struct aac_cmd *acp = &softs->sync_ac;
310711348SZhongyan.Gu@Sun.COM
310811636SXin.Chen@Sun.COM acp->flags = AAC_CMD_SYNC | AAC_CMD_IN_SYNC_SLOT;
310911636SXin.Chen@Sun.COM if (softs->state & AAC_STATE_INTR)
311011636SXin.Chen@Sun.COM acp->flags |= AAC_CMD_NO_CB;
311111636SXin.Chen@Sun.COM else
311211636SXin.Chen@Sun.COM acp->flags |= AAC_CMD_NO_INTR;
311311636SXin.Chen@Sun.COM
311411348SZhongyan.Gu@Sun.COM acp->ac_comp = aac_sync_complete;
311511348SZhongyan.Gu@Sun.COM acp->timeout = AAC_SYNC_TIMEOUT;
311611348SZhongyan.Gu@Sun.COM acp->fib_size = fibsize;
311711636SXin.Chen@Sun.COM
31185678Spl196000 /*
311911348SZhongyan.Gu@Sun.COM * Only need to setup sync fib header, caller should have init
312011348SZhongyan.Gu@Sun.COM * fib data
31215678Spl196000 */
312211348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, cmd);
312311348SZhongyan.Gu@Sun.COM
312411636SXin.Chen@Sun.COM (void) ddi_dma_sync(acp->slotp->fib_dma_handle, 0, fibsize,
312511636SXin.Chen@Sun.COM DDI_DMA_SYNC_FORDEV);
312611636SXin.Chen@Sun.COM
312711348SZhongyan.Gu@Sun.COM aac_start_io(softs, acp);
312811348SZhongyan.Gu@Sun.COM
312911636SXin.Chen@Sun.COM if (softs->state & AAC_STATE_INTR)
313011636SXin.Chen@Sun.COM return (aac_do_sync_io(softs, acp));
313111636SXin.Chen@Sun.COM else
313211636SXin.Chen@Sun.COM return (aac_do_poll_io(softs, acp));
31335678Spl196000 }
31345678Spl196000
31355678Spl196000 static void
aac_cmd_initq(struct aac_cmd_queue * q)31365678Spl196000 aac_cmd_initq(struct aac_cmd_queue *q)
31375678Spl196000 {
31385678Spl196000 q->q_head = NULL;
31395678Spl196000 q->q_tail = (struct aac_cmd *)&q->q_head;
31405678Spl196000 }
31415678Spl196000
31425678Spl196000 /*
31435678Spl196000 * Remove a cmd from the head of q
31445678Spl196000 */
31455678Spl196000 static struct aac_cmd *
aac_cmd_dequeue(struct aac_cmd_queue * q)31465678Spl196000 aac_cmd_dequeue(struct aac_cmd_queue *q)
31475678Spl196000 {
31485678Spl196000 struct aac_cmd *acp;
31495678Spl196000
31505678Spl196000 _NOTE(ASSUMING_PROTECTED(*q))
31515678Spl196000
31525678Spl196000 if ((acp = q->q_head) != NULL) {
31535678Spl196000 if ((q->q_head = acp->next) != NULL)
31545678Spl196000 acp->next = NULL;
31555678Spl196000 else
31565678Spl196000 q->q_tail = (struct aac_cmd *)&q->q_head;
31575678Spl196000 acp->prev = NULL;
31585678Spl196000 }
31595678Spl196000 return (acp);
31605678Spl196000 }
31615678Spl196000
31625678Spl196000 /*
31635678Spl196000 * Add a cmd to the tail of q
31645678Spl196000 */
31655678Spl196000 static void
aac_cmd_enqueue(struct aac_cmd_queue * q,struct aac_cmd * acp)31665678Spl196000 aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
31675678Spl196000 {
31685678Spl196000 ASSERT(acp->next == NULL);
31695678Spl196000 acp->prev = q->q_tail;
31705678Spl196000 q->q_tail->next = acp;
31715678Spl196000 q->q_tail = acp;
31725678Spl196000 }
31735678Spl196000
31745678Spl196000 /*
31755678Spl196000 * Remove the cmd ac from q
31765678Spl196000 */
31775678Spl196000 static void
aac_cmd_delete(struct aac_cmd_queue * q,struct aac_cmd * acp)31785678Spl196000 aac_cmd_delete(struct aac_cmd_queue *q, struct aac_cmd *acp)
31795678Spl196000 {
31805678Spl196000 if (acp->prev) {
31815678Spl196000 if ((acp->prev->next = acp->next) != NULL) {
31825678Spl196000 acp->next->prev = acp->prev;
31835678Spl196000 acp->next = NULL;
31845678Spl196000 } else {
31855678Spl196000 q->q_tail = acp->prev;
31865678Spl196000 }
31875678Spl196000 acp->prev = NULL;
31885678Spl196000 }
31895678Spl196000 /* ac is not in the queue */
31905678Spl196000 }
31915678Spl196000
31925678Spl196000 /*
31935678Spl196000 * Atomically insert an entry into the nominated queue, returns 0 on success or
31945678Spl196000 * AACERR if the queue is full.
31955678Spl196000 *
31965678Spl196000 * Note: it would be more efficient to defer notifying the controller in
31975678Spl196000 * the case where we may be inserting several entries in rapid succession,
31985678Spl196000 * but implementing this usefully may be difficult (it would involve a
31995678Spl196000 * separate queue/notify interface).
32005678Spl196000 */
32015678Spl196000 static int
aac_fib_enqueue(struct aac_softstate * softs,int queue,uint32_t fib_addr,uint32_t fib_size)32025678Spl196000 aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
32035678Spl196000 uint32_t fib_size)
32045678Spl196000 {
32055678Spl196000 ddi_dma_handle_t dma = softs->comm_space_dma_handle;
32065678Spl196000 ddi_acc_handle_t acc = softs->comm_space_acc_handle;
32075678Spl196000 uint32_t pi, ci;
32085678Spl196000
32095678Spl196000 DBCALLED(softs, 2);
32105678Spl196000
32115678Spl196000 ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
32125678Spl196000
32135678Spl196000 /* Get the producer/consumer indices */
32147100Spl196000 (void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
32157100Spl196000 (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
32165678Spl196000 DDI_DMA_SYNC_FORCPU);
32175678Spl196000 if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
32185678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
32195678Spl196000 return (AACERR);
32205678Spl196000 }
32215678Spl196000
32225678Spl196000 pi = ddi_get32(acc,
32235678Spl196000 &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
32245678Spl196000 ci = ddi_get32(acc,
32255678Spl196000 &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
32265678Spl196000
32275678Spl196000 /*
32285678Spl196000 * Wrap the queue first before we check the queue to see
32295678Spl196000 * if it is full
32305678Spl196000 */
32315678Spl196000 if (pi >= aac_qinfo[queue].size)
32325678Spl196000 pi = 0;
32335678Spl196000
32345678Spl196000 /* XXX queue full */
32355678Spl196000 if ((pi + 1) == ci)
32365678Spl196000 return (AACERR);
32375678Spl196000
32385678Spl196000 /* Fill in queue entry */
32395678Spl196000 ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_size), fib_size);
32405678Spl196000 ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_addr), fib_addr);
32417100Spl196000 (void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
32427100Spl196000 (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
32435678Spl196000 DDI_DMA_SYNC_FORDEV);
32445678Spl196000
32455678Spl196000 /* Update producer index */
32465678Spl196000 ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX],
32475678Spl196000 pi + 1);
32485678Spl196000 (void) ddi_dma_sync(dma,
32497100Spl196000 (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] - \
32507100Spl196000 (uintptr_t)softs->comm_space, sizeof (uint32_t),
32515678Spl196000 DDI_DMA_SYNC_FORDEV);
32525678Spl196000
32535678Spl196000 if (aac_qinfo[queue].notify != 0)
32545678Spl196000 AAC_NOTIFY(softs, aac_qinfo[queue].notify);
32555678Spl196000 return (AACOK);
32565678Spl196000 }
32575678Spl196000
32585678Spl196000 /*
32595678Spl196000 * Atomically remove one entry from the nominated queue, returns 0 on
32605678Spl196000 * success or AACERR if the queue is empty.
32615678Spl196000 */
32625678Spl196000 static int
aac_fib_dequeue(struct aac_softstate * softs,int queue,int * idxp)32635678Spl196000 aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
32645678Spl196000 {
32655678Spl196000 ddi_acc_handle_t acc = softs->comm_space_acc_handle;
32665678Spl196000 ddi_dma_handle_t dma = softs->comm_space_dma_handle;
32675678Spl196000 uint32_t pi, ci;
32685678Spl196000 int unfull = 0;
32695678Spl196000
32705678Spl196000 DBCALLED(softs, 2);
32715678Spl196000
32725678Spl196000 ASSERT(idxp);
32735678Spl196000
32745678Spl196000 /* Get the producer/consumer indices */
32757100Spl196000 (void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
32767100Spl196000 (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
32775678Spl196000 DDI_DMA_SYNC_FORCPU);
32785678Spl196000 pi = ddi_get32(acc,
32795678Spl196000 &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
32805678Spl196000 ci = ddi_get32(acc,
32815678Spl196000 &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
32825678Spl196000
32835678Spl196000 /* Check for queue empty */
32845678Spl196000 if (ci == pi)
32855678Spl196000 return (AACERR);
32865678Spl196000
32875678Spl196000 if (pi >= aac_qinfo[queue].size)
32885678Spl196000 pi = 0;
32895678Spl196000
32905678Spl196000 /* Check for queue full */
32915678Spl196000 if (ci == pi + 1)
32925678Spl196000 unfull = 1;
32935678Spl196000
32945678Spl196000 /*
32955678Spl196000 * The controller does not wrap the queue,
32965678Spl196000 * so we have to do it by ourselves
32975678Spl196000 */
32985678Spl196000 if (ci >= aac_qinfo[queue].size)
32995678Spl196000 ci = 0;
33005678Spl196000
33015678Spl196000 /* Fetch the entry */
33027100Spl196000 (void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
33037100Spl196000 (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
33045678Spl196000 DDI_DMA_SYNC_FORCPU);
33055678Spl196000 if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
33065678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
33075678Spl196000 return (AACERR);
33085678Spl196000 }
33095678Spl196000
33105678Spl196000 switch (queue) {
33115678Spl196000 case AAC_HOST_NORM_RESP_Q:
33125678Spl196000 case AAC_HOST_HIGH_RESP_Q:
33135678Spl196000 *idxp = ddi_get32(acc,
33145678Spl196000 &(softs->qentries[queue] + ci)->aq_fib_addr);
33155678Spl196000 break;
33165678Spl196000
33175678Spl196000 case AAC_HOST_NORM_CMD_Q:
33185678Spl196000 case AAC_HOST_HIGH_CMD_Q:
33195678Spl196000 *idxp = ddi_get32(acc,
33205678Spl196000 &(softs->qentries[queue] + ci)->aq_fib_addr) / AAC_FIB_SIZE;
33215678Spl196000 break;
33225678Spl196000
33235678Spl196000 default:
33245678Spl196000 cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
33255678Spl196000 return (AACERR);
33265678Spl196000 }
33275678Spl196000
33285678Spl196000 /* Update consumer index */
33295678Spl196000 ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX],
33305678Spl196000 ci + 1);
33315678Spl196000 (void) ddi_dma_sync(dma,
33327100Spl196000 (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX] - \
33337100Spl196000 (uintptr_t)softs->comm_space, sizeof (uint32_t),
33345678Spl196000 DDI_DMA_SYNC_FORDEV);
33355678Spl196000
33365678Spl196000 if (unfull && aac_qinfo[queue].notify != 0)
33375678Spl196000 AAC_NOTIFY(softs, aac_qinfo[queue].notify);
33385678Spl196000 return (AACOK);
33395678Spl196000 }
33405678Spl196000
33415678Spl196000 static struct aac_mntinforesp *
aac_get_mntinfo(struct aac_softstate * softs,int cid)334211348SZhongyan.Gu@Sun.COM aac_get_mntinfo(struct aac_softstate *softs, int cid)
334311348SZhongyan.Gu@Sun.COM {
334411348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
334511348SZhongyan.Gu@Sun.COM struct aac_fib *fibp = softs->sync_ac.slotp->fibp;
33465678Spl196000 struct aac_mntinfo *mi = (struct aac_mntinfo *)&fibp->data[0];
33475678Spl196000 struct aac_mntinforesp *mir;
33485678Spl196000
33495678Spl196000 ddi_put32(acc, &mi->Command, /* Use 64-bit LBA if enabled */
33505678Spl196000 (softs->flags & AAC_FLAGS_LBA_64BIT) ?
33515678Spl196000 VM_NameServe64 : VM_NameServe);
33525678Spl196000 ddi_put32(acc, &mi->MntType, FT_FILESYS);
33535678Spl196000 ddi_put32(acc, &mi->MntCount, cid);
33545678Spl196000
33555678Spl196000 if (aac_sync_fib(softs, ContainerCommand,
33565678Spl196000 AAC_FIB_SIZEOF(struct aac_mntinfo)) == AACERR) {
33575678Spl196000 AACDB_PRINT(softs, CE_WARN, "Error probe container %d", cid);
33585678Spl196000 return (NULL);
33595678Spl196000 }
33605678Spl196000
33615678Spl196000 mir = (struct aac_mntinforesp *)&fibp->data[0];
33625678Spl196000 if (ddi_get32(acc, &mir->Status) == ST_OK)
33635678Spl196000 return (mir);
33645678Spl196000 return (NULL);
33655678Spl196000 }
33665678Spl196000
33675678Spl196000 static int
aac_get_container_count(struct aac_softstate * softs,int * count)33685678Spl196000 aac_get_container_count(struct aac_softstate *softs, int *count)
33695678Spl196000 {
337011348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
33715678Spl196000 struct aac_mntinforesp *mir;
337211348SZhongyan.Gu@Sun.COM int rval;
337311348SZhongyan.Gu@Sun.COM
337411348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
337511348SZhongyan.Gu@Sun.COM acc = softs->sync_ac.slotp->fib_acc_handle;
337611348SZhongyan.Gu@Sun.COM
337711348SZhongyan.Gu@Sun.COM if ((mir = aac_get_mntinfo(softs, 0)) == NULL) {
337811348SZhongyan.Gu@Sun.COM rval = AACERR;
337911348SZhongyan.Gu@Sun.COM goto finish;
338011348SZhongyan.Gu@Sun.COM }
33815678Spl196000 *count = ddi_get32(acc, &mir->MntRespCount);
33825678Spl196000 if (*count > AAC_MAX_LD) {
33835678Spl196000 AACDB_PRINT(softs, CE_CONT,
33845678Spl196000 "container count(%d) > AAC_MAX_LD", *count);
338511348SZhongyan.Gu@Sun.COM rval = AACERR;
338611348SZhongyan.Gu@Sun.COM goto finish;
338711348SZhongyan.Gu@Sun.COM }
338811348SZhongyan.Gu@Sun.COM rval = AACOK;
338911348SZhongyan.Gu@Sun.COM
339011348SZhongyan.Gu@Sun.COM finish:
339111348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, &softs->sync_ac);
339211348SZhongyan.Gu@Sun.COM return (rval);
33935678Spl196000 }
33945678Spl196000
33955678Spl196000 static int
aac_get_container_uid(struct aac_softstate * softs,uint32_t cid,uint32_t * uid)33965678Spl196000 aac_get_container_uid(struct aac_softstate *softs, uint32_t cid, uint32_t *uid)
33975678Spl196000 {
339811348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
33995678Spl196000 struct aac_Container *ct = (struct aac_Container *) \
340011348SZhongyan.Gu@Sun.COM &softs->sync_ac.slotp->fibp->data[0];
34015678Spl196000
34025678Spl196000 bzero(ct, sizeof (*ct) - CT_PACKET_SIZE);
34035678Spl196000 ddi_put32(acc, &ct->Command, VM_ContainerConfig);
34045678Spl196000 ddi_put32(acc, &ct->CTCommand.command, CT_CID_TO_32BITS_UID);
34055678Spl196000 ddi_put32(acc, &ct->CTCommand.param[0], cid);
34065678Spl196000
34075678Spl196000 if (aac_sync_fib(softs, ContainerCommand,
34085678Spl196000 AAC_FIB_SIZEOF(struct aac_Container)) == AACERR)
34095678Spl196000 return (AACERR);
34105678Spl196000 if (ddi_get32(acc, &ct->CTCommand.param[0]) != CT_OK)
34115678Spl196000 return (AACERR);
34125678Spl196000
34135678Spl196000 *uid = ddi_get32(acc, &ct->CTCommand.param[1]);
34145678Spl196000 return (AACOK);
34155678Spl196000 }
34165678Spl196000
341711348SZhongyan.Gu@Sun.COM /*
341811348SZhongyan.Gu@Sun.COM * Request information of the container cid
341911348SZhongyan.Gu@Sun.COM */
342011348SZhongyan.Gu@Sun.COM static struct aac_mntinforesp *
aac_get_container_info(struct aac_softstate * softs,int cid)342111348SZhongyan.Gu@Sun.COM aac_get_container_info(struct aac_softstate *softs, int cid)
342211348SZhongyan.Gu@Sun.COM {
342311348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
342411348SZhongyan.Gu@Sun.COM struct aac_mntinforesp *mir;
342511348SZhongyan.Gu@Sun.COM int rval_uid;
342611348SZhongyan.Gu@Sun.COM uint32_t uid;
342711348SZhongyan.Gu@Sun.COM
342811348SZhongyan.Gu@Sun.COM /* Get container UID first so that it will not overwrite mntinfo */
342911348SZhongyan.Gu@Sun.COM rval_uid = aac_get_container_uid(softs, cid, &uid);
343011348SZhongyan.Gu@Sun.COM
343111348SZhongyan.Gu@Sun.COM /* Get container basic info */
343211348SZhongyan.Gu@Sun.COM if ((mir = aac_get_mntinfo(softs, cid)) == NULL) {
343311348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_CONT,
343411348SZhongyan.Gu@Sun.COM "query container %d info failed", cid);
343511348SZhongyan.Gu@Sun.COM return (NULL);
343611348SZhongyan.Gu@Sun.COM }
343711348SZhongyan.Gu@Sun.COM if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE)
343811348SZhongyan.Gu@Sun.COM return (mir);
343911348SZhongyan.Gu@Sun.COM if (rval_uid != AACOK) {
344011348SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_CONT,
344111348SZhongyan.Gu@Sun.COM "query container %d uid failed", cid);
344211348SZhongyan.Gu@Sun.COM return (NULL);
344311348SZhongyan.Gu@Sun.COM }
344411348SZhongyan.Gu@Sun.COM
344511348SZhongyan.Gu@Sun.COM ddi_put32(acc, &mir->Status, uid);
344611348SZhongyan.Gu@Sun.COM return (mir);
344711348SZhongyan.Gu@Sun.COM }
344811348SZhongyan.Gu@Sun.COM
344911964SXin.Chen@Sun.COM static enum aac_cfg_event
aac_probe_container(struct aac_softstate * softs,uint32_t cid)34505678Spl196000 aac_probe_container(struct aac_softstate *softs, uint32_t cid)
34515678Spl196000 {
345211964SXin.Chen@Sun.COM enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
34535678Spl196000 struct aac_container *dvp = &softs->containers[cid];
345411964SXin.Chen@Sun.COM struct aac_mntinforesp *mir;
345511348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
345611348SZhongyan.Gu@Sun.COM
345711348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
345811348SZhongyan.Gu@Sun.COM acc = softs->sync_ac.slotp->fib_acc_handle;
34595678Spl196000
34605678Spl196000 /* Get container basic info */
346111348SZhongyan.Gu@Sun.COM if ((mir = aac_get_container_info(softs, cid)) == NULL) {
346211964SXin.Chen@Sun.COM /* AAC_CFG_NULL_NOEXIST */
346311348SZhongyan.Gu@Sun.COM goto finish;
346411348SZhongyan.Gu@Sun.COM }
34655678Spl196000
34665678Spl196000 if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE) {
34677567SXin.Chen@Sun.COM if (AAC_DEV_IS_VALID(&dvp->dev)) {
34685678Spl196000 AACDB_PRINT(softs, CE_NOTE,
34695678Spl196000 ">>> Container %d deleted", cid);
34707567SXin.Chen@Sun.COM dvp->dev.flags &= ~AAC_DFLAG_VALID;
347111964SXin.Chen@Sun.COM event = AAC_CFG_DELETE;
347211964SXin.Chen@Sun.COM }
347311964SXin.Chen@Sun.COM /* AAC_CFG_NULL_NOEXIST */
34745678Spl196000 } else {
347511964SXin.Chen@Sun.COM uint64_t size;
347611964SXin.Chen@Sun.COM uint32_t uid;
347711964SXin.Chen@Sun.COM
347811964SXin.Chen@Sun.COM event = AAC_CFG_NULL_EXIST;
347911964SXin.Chen@Sun.COM
34805678Spl196000 size = AAC_MIR_SIZE(softs, acc, mir);
348111348SZhongyan.Gu@Sun.COM uid = ddi_get32(acc, &mir->Status);
34827567SXin.Chen@Sun.COM if (AAC_DEV_IS_VALID(&dvp->dev)) {
34835678Spl196000 if (dvp->uid != uid) {
34845678Spl196000 AACDB_PRINT(softs, CE_WARN,
34855678Spl196000 ">>> Container %u uid changed to %d",
34865678Spl196000 cid, uid);
34875678Spl196000 dvp->uid = uid;
348811964SXin.Chen@Sun.COM event = AAC_CFG_CHANGE;
34895678Spl196000 }
34905678Spl196000 if (dvp->size != size) {
34915678Spl196000 AACDB_PRINT(softs, CE_NOTE,
34925678Spl196000 ">>> Container %u size changed to %"PRIu64,
34935678Spl196000 cid, size);
34945678Spl196000 dvp->size = size;
349511964SXin.Chen@Sun.COM event = AAC_CFG_CHANGE;
34965678Spl196000 }
34975678Spl196000 } else { /* Init new container */
34985678Spl196000 AACDB_PRINT(softs, CE_NOTE,
34997567SXin.Chen@Sun.COM ">>> Container %d added: " \
35007567SXin.Chen@Sun.COM "size=0x%x.%08x, type=%d, name=%s",
35017567SXin.Chen@Sun.COM cid,
35027567SXin.Chen@Sun.COM ddi_get32(acc, &mir->MntObj.CapacityHigh),
35037567SXin.Chen@Sun.COM ddi_get32(acc, &mir->MntObj.Capacity),
35047567SXin.Chen@Sun.COM ddi_get32(acc, &mir->MntObj.VolType),
35057567SXin.Chen@Sun.COM mir->MntObj.FileSystemName);
35067567SXin.Chen@Sun.COM dvp->dev.flags |= AAC_DFLAG_VALID;
35077567SXin.Chen@Sun.COM dvp->dev.type = AAC_DEV_LD;
35085678Spl196000
35095678Spl196000 dvp->cid = cid;
35105678Spl196000 dvp->uid = uid;
35115678Spl196000 dvp->size = size;
35125678Spl196000 dvp->locked = 0;
35135678Spl196000 dvp->deleted = 0;
351411964SXin.Chen@Sun.COM
351511964SXin.Chen@Sun.COM event = AAC_CFG_ADD;
351611964SXin.Chen@Sun.COM }
351711964SXin.Chen@Sun.COM }
351811348SZhongyan.Gu@Sun.COM
351911348SZhongyan.Gu@Sun.COM finish:
352011348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, &softs->sync_ac);
352111964SXin.Chen@Sun.COM return (event);
35225678Spl196000 }
35235678Spl196000
35245678Spl196000 /*
35255678Spl196000 * Do a rescan of all the possible containers and update the container list
35267567SXin.Chen@Sun.COM * with newly online/offline containers, and prepare for autoconfiguration.
35275678Spl196000 */
35285678Spl196000 static int
aac_probe_containers(struct aac_softstate * softs)35295678Spl196000 aac_probe_containers(struct aac_softstate *softs)
35305678Spl196000 {
35315678Spl196000 int i, count, total;
35325678Spl196000
35335678Spl196000 /* Loop over possible containers */
35345678Spl196000 count = softs->container_count;
35355678Spl196000 if (aac_get_container_count(softs, &count) == AACERR)
35365678Spl196000 return (AACERR);
353711964SXin.Chen@Sun.COM
35385678Spl196000 for (i = total = 0; i < count; i++) {
353911964SXin.Chen@Sun.COM enum aac_cfg_event event = aac_probe_container(softs, i);
354011964SXin.Chen@Sun.COM if ((event != AAC_CFG_NULL_NOEXIST) &&
354111964SXin.Chen@Sun.COM (event != AAC_CFG_NULL_EXIST)) {
354211964SXin.Chen@Sun.COM (void) aac_handle_dr(softs, i, -1, event);
35435678Spl196000 total++;
354411964SXin.Chen@Sun.COM }
354511964SXin.Chen@Sun.COM }
354611964SXin.Chen@Sun.COM
35475678Spl196000 if (count < softs->container_count) {
35485678Spl196000 struct aac_container *dvp;
35495678Spl196000
35505678Spl196000 for (dvp = &softs->containers[count];
35515678Spl196000 dvp < &softs->containers[softs->container_count]; dvp++) {
35527567SXin.Chen@Sun.COM if (!AAC_DEV_IS_VALID(&dvp->dev))
35535678Spl196000 continue;
35545678Spl196000 AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
35555678Spl196000 dvp->cid);
35567567SXin.Chen@Sun.COM dvp->dev.flags &= ~AAC_DFLAG_VALID;
355711964SXin.Chen@Sun.COM (void) aac_handle_dr(softs, dvp->cid, -1,
355811964SXin.Chen@Sun.COM AAC_CFG_DELETE);
355911964SXin.Chen@Sun.COM }
356011964SXin.Chen@Sun.COM }
356111964SXin.Chen@Sun.COM
35625678Spl196000 softs->container_count = count;
35635678Spl196000 AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
35645678Spl196000 return (AACOK);
35655678Spl196000 }
35665678Spl196000
35675678Spl196000 static int
aac_probe_jbod(struct aac_softstate * softs,int tgt,int event)3568*12408SZhongyan.Gu@Sun.COM aac_probe_jbod(struct aac_softstate *softs, int tgt, int event)
3569*12408SZhongyan.Gu@Sun.COM {
3570*12408SZhongyan.Gu@Sun.COM ASSERT(AAC_MAX_LD <= tgt < AAC_MAX_DEV(softs));
3571*12408SZhongyan.Gu@Sun.COM struct aac_device *dvp;
3572*12408SZhongyan.Gu@Sun.COM dvp = AAC_DEV(softs, tgt);
3573*12408SZhongyan.Gu@Sun.COM
3574*12408SZhongyan.Gu@Sun.COM switch (event) {
3575*12408SZhongyan.Gu@Sun.COM case AAC_CFG_ADD:
3576*12408SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE,
3577*12408SZhongyan.Gu@Sun.COM ">>> Jbod %d added", tgt - AAC_MAX_LD);
3578*12408SZhongyan.Gu@Sun.COM dvp->flags |= AAC_DFLAG_VALID;
3579*12408SZhongyan.Gu@Sun.COM dvp->type = AAC_DEV_PD;
3580*12408SZhongyan.Gu@Sun.COM break;
3581*12408SZhongyan.Gu@Sun.COM case AAC_CFG_DELETE:
3582*12408SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE,
3583*12408SZhongyan.Gu@Sun.COM ">>> Jbod %d deleted", tgt - AAC_MAX_LD);
3584*12408SZhongyan.Gu@Sun.COM dvp->flags &= ~AAC_DFLAG_VALID;
3585*12408SZhongyan.Gu@Sun.COM break;
3586*12408SZhongyan.Gu@Sun.COM default:
3587*12408SZhongyan.Gu@Sun.COM return (AACERR);
3588*12408SZhongyan.Gu@Sun.COM }
3589*12408SZhongyan.Gu@Sun.COM (void) aac_handle_dr(softs, tgt, 0, event);
3590*12408SZhongyan.Gu@Sun.COM return (AACOK);
3591*12408SZhongyan.Gu@Sun.COM }
3592*12408SZhongyan.Gu@Sun.COM
3593*12408SZhongyan.Gu@Sun.COM static int
aac_alloc_comm_space(struct aac_softstate * softs)35945678Spl196000 aac_alloc_comm_space(struct aac_softstate *softs)
35955678Spl196000 {
35965678Spl196000 size_t rlen;
35975678Spl196000 ddi_dma_cookie_t cookie;
35985678Spl196000 uint_t cookien;
35995678Spl196000
36005678Spl196000 /* Allocate DMA for comm. space */
36015678Spl196000 if (ddi_dma_alloc_handle(
36025678Spl196000 softs->devinfo_p,
36035678Spl196000 &softs->addr_dma_attr,
36045678Spl196000 DDI_DMA_SLEEP,
36055678Spl196000 NULL,
36065678Spl196000 &softs->comm_space_dma_handle) != DDI_SUCCESS) {
36075678Spl196000 AACDB_PRINT(softs, CE_WARN,
36085678Spl196000 "Cannot alloc dma handle for communication area");
36095678Spl196000 goto error;
36105678Spl196000 }
36115678Spl196000 if (ddi_dma_mem_alloc(
36125678Spl196000 softs->comm_space_dma_handle,
36135678Spl196000 sizeof (struct aac_comm_space),
36147567SXin.Chen@Sun.COM &softs->acc_attr,
36155678Spl196000 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
36165678Spl196000 DDI_DMA_SLEEP,
36175678Spl196000 NULL,
36185678Spl196000 (caddr_t *)&softs->comm_space,
36195678Spl196000 &rlen,
36205678Spl196000 &softs->comm_space_acc_handle) != DDI_SUCCESS) {
36215678Spl196000 AACDB_PRINT(softs, CE_WARN,
36225678Spl196000 "Cannot alloc mem for communication area");
36235678Spl196000 goto error;
36245678Spl196000 }
36255678Spl196000 if (ddi_dma_addr_bind_handle(
36265678Spl196000 softs->comm_space_dma_handle,
36275678Spl196000 NULL,
36285678Spl196000 (caddr_t)softs->comm_space,
36295678Spl196000 sizeof (struct aac_comm_space),
36305678Spl196000 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
36315678Spl196000 DDI_DMA_SLEEP,
36325678Spl196000 NULL,
36335678Spl196000 &cookie,
36345678Spl196000 &cookien) != DDI_DMA_MAPPED) {
36355678Spl196000 AACDB_PRINT(softs, CE_WARN,
36365678Spl196000 "DMA bind failed for communication area");
36375678Spl196000 goto error;
36385678Spl196000 }
36395678Spl196000 softs->comm_space_phyaddr = cookie.dmac_address;
36405678Spl196000
36415678Spl196000 return (AACOK);
36425678Spl196000 error:
36435678Spl196000 if (softs->comm_space_acc_handle) {
36445678Spl196000 ddi_dma_mem_free(&softs->comm_space_acc_handle);
36455678Spl196000 softs->comm_space_acc_handle = NULL;
36465678Spl196000 }
36475678Spl196000 if (softs->comm_space_dma_handle) {
36485678Spl196000 ddi_dma_free_handle(&softs->comm_space_dma_handle);
36495678Spl196000 softs->comm_space_dma_handle = NULL;
36505678Spl196000 }
36515678Spl196000 return (AACERR);
36525678Spl196000 }
36535678Spl196000
36545678Spl196000 static void
aac_free_comm_space(struct aac_softstate * softs)36555678Spl196000 aac_free_comm_space(struct aac_softstate *softs)
36565678Spl196000 {
36575678Spl196000
36585678Spl196000 (void) ddi_dma_unbind_handle(softs->comm_space_dma_handle);
36595678Spl196000 ddi_dma_mem_free(&softs->comm_space_acc_handle);
36605678Spl196000 softs->comm_space_acc_handle = NULL;
36615678Spl196000 ddi_dma_free_handle(&softs->comm_space_dma_handle);
36625678Spl196000 softs->comm_space_dma_handle = NULL;
36635678Spl196000 softs->comm_space_phyaddr = NULL;
36645678Spl196000 }
36655678Spl196000
36665678Spl196000 /*
36675678Spl196000 * Initialize the data structures that are required for the communication
36685678Spl196000 * interface to operate
36695678Spl196000 */
36705678Spl196000 static int
aac_setup_comm_space(struct aac_softstate * softs)36715678Spl196000 aac_setup_comm_space(struct aac_softstate *softs)
36725678Spl196000 {
36735678Spl196000 ddi_dma_handle_t dma = softs->comm_space_dma_handle;
36745678Spl196000 ddi_acc_handle_t acc = softs->comm_space_acc_handle;
36755678Spl196000 uint32_t comm_space_phyaddr;
36765678Spl196000 struct aac_adapter_init *initp;
36775678Spl196000 int qoffset;
36785678Spl196000
36795678Spl196000 comm_space_phyaddr = softs->comm_space_phyaddr;
36805678Spl196000
36815678Spl196000 /* Setup adapter init struct */
36825678Spl196000 initp = &softs->comm_space->init_data;
36835678Spl196000 bzero(initp, sizeof (struct aac_adapter_init));
36845678Spl196000
36855678Spl196000 ddi_put32(acc, &initp->InitStructRevision, AAC_INIT_STRUCT_REVISION);
36865678Spl196000 ddi_put32(acc, &initp->HostElapsedSeconds, ddi_get_time());
36875678Spl196000
36885678Spl196000 /* Setup new/old comm. specific data */
36895678Spl196000 if (softs->flags & AAC_FLAGS_RAW_IO) {
369010976SZhongyan.Gu@Sun.COM uint32_t init_flags = 0;
369110976SZhongyan.Gu@Sun.COM
369210976SZhongyan.Gu@Sun.COM if (softs->flags & AAC_FLAGS_NEW_COMM)
369310976SZhongyan.Gu@Sun.COM init_flags |= AAC_INIT_FLAGS_NEW_COMM_SUPPORTED;
369410976SZhongyan.Gu@Sun.COM /* AAC_SUPPORTED_POWER_MANAGEMENT */
369510976SZhongyan.Gu@Sun.COM init_flags |= AAC_INIT_FLAGS_DRIVER_SUPPORTS_PM;
369610976SZhongyan.Gu@Sun.COM init_flags |= AAC_INIT_FLAGS_DRIVER_USES_UTC_TIME;
369710976SZhongyan.Gu@Sun.COM
36985678Spl196000 ddi_put32(acc, &initp->InitStructRevision,
36995678Spl196000 AAC_INIT_STRUCT_REVISION_4);
370010976SZhongyan.Gu@Sun.COM ddi_put32(acc, &initp->InitFlags, init_flags);
37015678Spl196000 /* Setup the preferred settings */
37025678Spl196000 ddi_put32(acc, &initp->MaxIoCommands, softs->aac_max_fibs);
37035678Spl196000 ddi_put32(acc, &initp->MaxIoSize,
37045678Spl196000 (softs->aac_max_sectors << 9));
37055678Spl196000 ddi_put32(acc, &initp->MaxFibSize, softs->aac_max_fib_size);
37065678Spl196000 } else {
37075678Spl196000 /*
37085678Spl196000 * Tells the adapter about the physical location of various
37095678Spl196000 * important shared data structures
37105678Spl196000 */
37115678Spl196000 ddi_put32(acc, &initp->AdapterFibsPhysicalAddress,
37125678Spl196000 comm_space_phyaddr + \
37135678Spl196000 offsetof(struct aac_comm_space, adapter_fibs));
37145678Spl196000 ddi_put32(acc, &initp->AdapterFibsVirtualAddress, 0);
37155678Spl196000 ddi_put32(acc, &initp->AdapterFibAlign, AAC_FIB_SIZE);
37165678Spl196000 ddi_put32(acc, &initp->AdapterFibsSize,
37175678Spl196000 AAC_ADAPTER_FIBS * AAC_FIB_SIZE);
37185678Spl196000 ddi_put32(acc, &initp->PrintfBufferAddress,
37195678Spl196000 comm_space_phyaddr + \
37205678Spl196000 offsetof(struct aac_comm_space, adapter_print_buf));
37215678Spl196000 ddi_put32(acc, &initp->PrintfBufferSize,
37225678Spl196000 AAC_ADAPTER_PRINT_BUFSIZE);
37235678Spl196000 ddi_put32(acc, &initp->MiniPortRevision,
37245678Spl196000 AAC_INIT_STRUCT_MINIPORT_REVISION);
37255678Spl196000 ddi_put32(acc, &initp->HostPhysMemPages, AAC_MAX_PFN);
37265678Spl196000
37275678Spl196000 qoffset = (comm_space_phyaddr + \
37285678Spl196000 offsetof(struct aac_comm_space, qtable)) % \
37295678Spl196000 AAC_QUEUE_ALIGN;
37305678Spl196000 if (qoffset)
37315678Spl196000 qoffset = AAC_QUEUE_ALIGN - qoffset;
37325678Spl196000 softs->qtablep = (struct aac_queue_table *) \
37335678Spl196000 ((char *)&softs->comm_space->qtable + qoffset);
37345678Spl196000 ddi_put32(acc, &initp->CommHeaderAddress, comm_space_phyaddr + \
37355678Spl196000 offsetof(struct aac_comm_space, qtable) + qoffset);
37365678Spl196000
37375678Spl196000 /* Init queue table */
37385678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37395678Spl196000 qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_PRODUCER_INDEX],
37405678Spl196000 AAC_HOST_NORM_CMD_ENTRIES);
37415678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37425678Spl196000 qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_CONSUMER_INDEX],
37435678Spl196000 AAC_HOST_NORM_CMD_ENTRIES);
37445678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37455678Spl196000 qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
37465678Spl196000 AAC_HOST_HIGH_CMD_ENTRIES);
37475678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37485678Spl196000 qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
37495678Spl196000 AAC_HOST_HIGH_CMD_ENTRIES);
37505678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37515678Spl196000 qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_PRODUCER_INDEX],
37525678Spl196000 AAC_ADAP_NORM_CMD_ENTRIES);
37535678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37545678Spl196000 qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_CONSUMER_INDEX],
37555678Spl196000 AAC_ADAP_NORM_CMD_ENTRIES);
37565678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37575678Spl196000 qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
37585678Spl196000 AAC_ADAP_HIGH_CMD_ENTRIES);
37595678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37605678Spl196000 qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
37615678Spl196000 AAC_ADAP_HIGH_CMD_ENTRIES);
37625678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37635678Spl196000 qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_PRODUCER_INDEX],
37645678Spl196000 AAC_HOST_NORM_RESP_ENTRIES);
37655678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37665678Spl196000 qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_CONSUMER_INDEX],
37675678Spl196000 AAC_HOST_NORM_RESP_ENTRIES);
37685678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37695678Spl196000 qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
37705678Spl196000 AAC_HOST_HIGH_RESP_ENTRIES);
37715678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37725678Spl196000 qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
37735678Spl196000 AAC_HOST_HIGH_RESP_ENTRIES);
37745678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37755678Spl196000 qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_PRODUCER_INDEX],
37765678Spl196000 AAC_ADAP_NORM_RESP_ENTRIES);
37775678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37785678Spl196000 qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_CONSUMER_INDEX],
37795678Spl196000 AAC_ADAP_NORM_RESP_ENTRIES);
37805678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37815678Spl196000 qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
37825678Spl196000 AAC_ADAP_HIGH_RESP_ENTRIES);
37835678Spl196000 ddi_put32(acc, &softs->qtablep-> \
37845678Spl196000 qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
37855678Spl196000 AAC_ADAP_HIGH_RESP_ENTRIES);
37865678Spl196000
37875678Spl196000 /* Init queue entries */
37885678Spl196000 softs->qentries[AAC_HOST_NORM_CMD_Q] =
37895678Spl196000 &softs->qtablep->qt_HostNormCmdQueue[0];
37905678Spl196000 softs->qentries[AAC_HOST_HIGH_CMD_Q] =
37915678Spl196000 &softs->qtablep->qt_HostHighCmdQueue[0];
37925678Spl196000 softs->qentries[AAC_ADAP_NORM_CMD_Q] =
37935678Spl196000 &softs->qtablep->qt_AdapNormCmdQueue[0];
37945678Spl196000 softs->qentries[AAC_ADAP_HIGH_CMD_Q] =
37955678Spl196000 &softs->qtablep->qt_AdapHighCmdQueue[0];
37965678Spl196000 softs->qentries[AAC_HOST_NORM_RESP_Q] =
37975678Spl196000 &softs->qtablep->qt_HostNormRespQueue[0];
37985678Spl196000 softs->qentries[AAC_HOST_HIGH_RESP_Q] =
37995678Spl196000 &softs->qtablep->qt_HostHighRespQueue[0];
38005678Spl196000 softs->qentries[AAC_ADAP_NORM_RESP_Q] =
38015678Spl196000 &softs->qtablep->qt_AdapNormRespQueue[0];
38025678Spl196000 softs->qentries[AAC_ADAP_HIGH_RESP_Q] =
38035678Spl196000 &softs->qtablep->qt_AdapHighRespQueue[0];
38045678Spl196000 }
38055678Spl196000 (void) ddi_dma_sync(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
38065678Spl196000
38075678Spl196000 /* Send init structure to the card */
38085678Spl196000 if (aac_sync_mbcommand(softs, AAC_MONKER_INITSTRUCT,
38095678Spl196000 comm_space_phyaddr + \
38105678Spl196000 offsetof(struct aac_comm_space, init_data),
38115678Spl196000 0, 0, 0, NULL) == AACERR) {
38125678Spl196000 AACDB_PRINT(softs, CE_WARN,
38135678Spl196000 "Cannot send init structure to adapter");
38145678Spl196000 return (AACERR);
38155678Spl196000 }
38165678Spl196000
38175678Spl196000 return (AACOK);
38185678Spl196000 }
38195678Spl196000
38205678Spl196000 static uchar_t *
aac_vendor_id(struct aac_softstate * softs,uchar_t * buf)38215678Spl196000 aac_vendor_id(struct aac_softstate *softs, uchar_t *buf)
38225678Spl196000 {
38235678Spl196000 (void) memset(buf, ' ', AAC_VENDOR_LEN);
38245678Spl196000 bcopy(softs->vendor_name, buf, strlen(softs->vendor_name));
38255678Spl196000 return (buf + AAC_VENDOR_LEN);
38265678Spl196000 }
38275678Spl196000
38285678Spl196000 static uchar_t *
aac_product_id(struct aac_softstate * softs,uchar_t * buf)38295678Spl196000 aac_product_id(struct aac_softstate *softs, uchar_t *buf)
38305678Spl196000 {
38315678Spl196000 (void) memset(buf, ' ', AAC_PRODUCT_LEN);
38325678Spl196000 bcopy(softs->product_name, buf, strlen(softs->product_name));
38335678Spl196000 return (buf + AAC_PRODUCT_LEN);
38345678Spl196000 }
38355678Spl196000
38365678Spl196000 /*
38375678Spl196000 * Construct unit serial number from container uid
38385678Spl196000 */
38395678Spl196000 static uchar_t *
aac_lun_serialno(struct aac_softstate * softs,int tgt,uchar_t * buf)38405678Spl196000 aac_lun_serialno(struct aac_softstate *softs, int tgt, uchar_t *buf)
38415678Spl196000 {
38425678Spl196000 int i, d;
38437567SXin.Chen@Sun.COM uint32_t uid;
38447567SXin.Chen@Sun.COM
38457567SXin.Chen@Sun.COM ASSERT(tgt >= 0 && tgt < AAC_MAX_LD);
38467567SXin.Chen@Sun.COM
38477567SXin.Chen@Sun.COM uid = softs->containers[tgt].uid;
38485678Spl196000 for (i = 7; i >= 0; i--) {
38495678Spl196000 d = uid & 0xf;
38505678Spl196000 buf[i] = d > 9 ? 'A' + (d - 0xa) : '0' + d;
38515678Spl196000 uid >>= 4;
38525678Spl196000 }
38535678Spl196000 return (buf + 8);
38545678Spl196000 }
38555678Spl196000
38565678Spl196000 /*
38575678Spl196000 * SPC-3 7.5 INQUIRY command implementation
38585678Spl196000 */
38595678Spl196000 static void
aac_inquiry(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp)38605678Spl196000 aac_inquiry(struct aac_softstate *softs, struct scsi_pkt *pkt,
38615678Spl196000 union scsi_cdb *cdbp, struct buf *bp)
38625678Spl196000 {
38635678Spl196000 int tgt = pkt->pkt_address.a_target;
38645678Spl196000 char *b_addr = NULL;
38655678Spl196000 uchar_t page = cdbp->cdb_opaque[2];
38665678Spl196000
38675678Spl196000 if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_CMDDT) {
38685678Spl196000 /* Command Support Data is not supported */
38695678Spl196000 aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x24, 0x00, 0);
38705678Spl196000 return;
38715678Spl196000 }
38725678Spl196000
38735678Spl196000 if (bp && bp->b_un.b_addr && bp->b_bcount) {
38745678Spl196000 if (bp->b_flags & (B_PHYS | B_PAGEIO))
38755678Spl196000 bp_mapin(bp);
38765678Spl196000 b_addr = bp->b_un.b_addr;
38775678Spl196000 }
38785678Spl196000
38795678Spl196000 if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_EVPD) {
38805678Spl196000 uchar_t *vpdp = (uchar_t *)b_addr;
38815678Spl196000 uchar_t *idp, *sp;
38825678Spl196000
38835678Spl196000 /* SPC-3 8.4 Vital product data parameters */
38845678Spl196000 switch (page) {
38855678Spl196000 case 0x00:
38865678Spl196000 /* Supported VPD pages */
38876799Sjd218194 if (vpdp == NULL ||
38886799Sjd218194 bp->b_bcount < (AAC_VPD_PAGE_DATA + 3))
38895678Spl196000 return;
38905678Spl196000 bzero(vpdp, AAC_VPD_PAGE_LENGTH);
38915678Spl196000 vpdp[AAC_VPD_PAGE_CODE] = 0x00;
38925678Spl196000 vpdp[AAC_VPD_PAGE_LENGTH] = 3;
38935678Spl196000
38945678Spl196000 vpdp[AAC_VPD_PAGE_DATA] = 0x00;
38955678Spl196000 vpdp[AAC_VPD_PAGE_DATA + 1] = 0x80;
38965678Spl196000 vpdp[AAC_VPD_PAGE_DATA + 2] = 0x83;
38975678Spl196000
38985678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
38995678Spl196000 break;
39005678Spl196000
39015678Spl196000 case 0x80:
39025678Spl196000 /* Unit serial number page */
39036799Sjd218194 if (vpdp == NULL ||
39046799Sjd218194 bp->b_bcount < (AAC_VPD_PAGE_DATA + 8))
39055678Spl196000 return;
39065678Spl196000 bzero(vpdp, AAC_VPD_PAGE_LENGTH);
39075678Spl196000 vpdp[AAC_VPD_PAGE_CODE] = 0x80;
39085678Spl196000 vpdp[AAC_VPD_PAGE_LENGTH] = 8;
39095678Spl196000
39105678Spl196000 sp = &vpdp[AAC_VPD_PAGE_DATA];
39115678Spl196000 (void) aac_lun_serialno(softs, tgt, sp);
39125678Spl196000
39135678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
39145678Spl196000 break;
39155678Spl196000
39165678Spl196000 case 0x83:
39175678Spl196000 /* Device identification page */
39186799Sjd218194 if (vpdp == NULL ||
39196799Sjd218194 bp->b_bcount < (AAC_VPD_PAGE_DATA + 32))
39205678Spl196000 return;
39215678Spl196000 bzero(vpdp, AAC_VPD_PAGE_LENGTH);
39225678Spl196000 vpdp[AAC_VPD_PAGE_CODE] = 0x83;
39235678Spl196000
39245678Spl196000 idp = &vpdp[AAC_VPD_PAGE_DATA];
39255678Spl196000 bzero(idp, AAC_VPD_ID_LENGTH);
39265678Spl196000 idp[AAC_VPD_ID_CODESET] = 0x02;
39275678Spl196000 idp[AAC_VPD_ID_TYPE] = 0x01;
39285678Spl196000
39295678Spl196000 /*
39305678Spl196000 * SPC-3 Table 111 - Identifier type
39315678Spl196000 * One recommanded method of constructing the remainder
39325678Spl196000 * of identifier field is to concatenate the product
39335678Spl196000 * identification field from the standard INQUIRY data
39345678Spl196000 * field and the product serial number field from the
39355678Spl196000 * unit serial number page.
39365678Spl196000 */
39375678Spl196000 sp = &idp[AAC_VPD_ID_DATA];
39385678Spl196000 sp = aac_vendor_id(softs, sp);
39395678Spl196000 sp = aac_product_id(softs, sp);
39405678Spl196000 sp = aac_lun_serialno(softs, tgt, sp);
39417100Spl196000 idp[AAC_VPD_ID_LENGTH] = (uintptr_t)sp - \
39427100Spl196000 (uintptr_t)&idp[AAC_VPD_ID_DATA];
39437100Spl196000
39447100Spl196000 vpdp[AAC_VPD_PAGE_LENGTH] = (uintptr_t)sp - \
39457100Spl196000 (uintptr_t)&vpdp[AAC_VPD_PAGE_DATA];
39465678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
39475678Spl196000 break;
39485678Spl196000
39495678Spl196000 default:
39505678Spl196000 aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
39515678Spl196000 0x24, 0x00, 0);
39525678Spl196000 break;
39535678Spl196000 }
39545678Spl196000 } else {
39555678Spl196000 struct scsi_inquiry *inqp = (struct scsi_inquiry *)b_addr;
39565678Spl196000 size_t len = sizeof (struct scsi_inquiry);
39575678Spl196000
39585678Spl196000 if (page != 0) {
39595678Spl196000 aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
39605678Spl196000 0x24, 0x00, 0);
39615678Spl196000 return;
39625678Spl196000 }
39636799Sjd218194 if (inqp == NULL || bp->b_bcount < len)
39645678Spl196000 return;
39655678Spl196000
39665678Spl196000 bzero(inqp, len);
39675678Spl196000 inqp->inq_len = AAC_ADDITIONAL_LEN;
39685678Spl196000 inqp->inq_ansi = AAC_ANSI_VER;
39695678Spl196000 inqp->inq_rdf = AAC_RESP_DATA_FORMAT;
39705678Spl196000 (void) aac_vendor_id(softs, (uchar_t *)inqp->inq_vid);
39715678Spl196000 (void) aac_product_id(softs, (uchar_t *)inqp->inq_pid);
39725678Spl196000 bcopy("V1.0", inqp->inq_revision, 4);
39735678Spl196000 inqp->inq_cmdque = 1; /* enable tagged-queuing */
39745678Spl196000 /*
39755678Spl196000 * For "sd-max-xfer-size" property which may impact performance
39765678Spl196000 * when IO threads increase.
39775678Spl196000 */
39785678Spl196000 inqp->inq_wbus32 = 1;
39795678Spl196000
39805678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
39815678Spl196000 }
39825678Spl196000 }
39835678Spl196000
39845678Spl196000 /*
39855678Spl196000 * SPC-3 7.10 MODE SENSE command implementation
39865678Spl196000 */
39875678Spl196000 static void
aac_mode_sense(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp,int capacity)39885678Spl196000 aac_mode_sense(struct aac_softstate *softs, struct scsi_pkt *pkt,
39895678Spl196000 union scsi_cdb *cdbp, struct buf *bp, int capacity)
39905678Spl196000 {
39915678Spl196000 uchar_t pagecode;
39925678Spl196000 struct mode_header *headerp;
39936799Sjd218194 struct mode_header_g1 *g1_headerp;
39945678Spl196000 unsigned int ncyl;
39956799Sjd218194 caddr_t sense_data;
39966799Sjd218194 caddr_t next_page;
39976799Sjd218194 size_t sdata_size;
39986799Sjd218194 size_t pages_size;
39996799Sjd218194 int unsupport_page = 0;
40006799Sjd218194
40016799Sjd218194 ASSERT(cdbp->scc_cmd == SCMD_MODE_SENSE ||
40026799Sjd218194 cdbp->scc_cmd == SCMD_MODE_SENSE_G1);
40035678Spl196000
40045678Spl196000 if (!(bp && bp->b_un.b_addr && bp->b_bcount))
40055678Spl196000 return;
40065678Spl196000
40075678Spl196000 if (bp->b_flags & (B_PHYS | B_PAGEIO))
40085678Spl196000 bp_mapin(bp);
40095678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
40106799Sjd218194 pagecode = cdbp->cdb_un.sg.scsi[0] & 0x3F;
40116799Sjd218194
40126799Sjd218194 /* calculate the size of needed buffer */
40136799Sjd218194 if (cdbp->scc_cmd == SCMD_MODE_SENSE)
40146799Sjd218194 sdata_size = MODE_HEADER_LENGTH;
40156799Sjd218194 else /* must be SCMD_MODE_SENSE_G1 */
40166799Sjd218194 sdata_size = MODE_HEADER_LENGTH_G1;
40176799Sjd218194
40186799Sjd218194 pages_size = 0;
40195678Spl196000 switch (pagecode) {
40205678Spl196000 case SD_MODE_SENSE_PAGE3_CODE:
40216799Sjd218194 pages_size += sizeof (struct mode_format);
40226799Sjd218194 break;
40236799Sjd218194
40246799Sjd218194 case SD_MODE_SENSE_PAGE4_CODE:
40256799Sjd218194 pages_size += sizeof (struct mode_geometry);
40266799Sjd218194 break;
40276799Sjd218194
40286799Sjd218194 case MODEPAGE_CTRL_MODE:
40296799Sjd218194 if (softs->flags & AAC_FLAGS_LBA_64BIT) {
40306799Sjd218194 pages_size += sizeof (struct mode_control_scsi3);
40316799Sjd218194 } else {
40326799Sjd218194 unsupport_page = 1;
40336799Sjd218194 }
40346799Sjd218194 break;
40356799Sjd218194
40366799Sjd218194 case MODEPAGE_ALLPAGES:
40376799Sjd218194 if (softs->flags & AAC_FLAGS_LBA_64BIT) {
40386799Sjd218194 pages_size += sizeof (struct mode_format) +
40396799Sjd218194 sizeof (struct mode_geometry) +
40406799Sjd218194 sizeof (struct mode_control_scsi3);
40416799Sjd218194 } else {
40426799Sjd218194 pages_size += sizeof (struct mode_format) +
40436799Sjd218194 sizeof (struct mode_geometry);
40446799Sjd218194 }
40456799Sjd218194 break;
40466799Sjd218194
40476799Sjd218194 default:
40486799Sjd218194 /* unsupported pages */
40496799Sjd218194 unsupport_page = 1;
40506799Sjd218194 }
40516799Sjd218194
40526799Sjd218194 /* allocate buffer to fill the send data */
40536799Sjd218194 sdata_size += pages_size;
40546799Sjd218194 sense_data = kmem_zalloc(sdata_size, KM_SLEEP);
40556799Sjd218194
40566799Sjd218194 if (cdbp->scc_cmd == SCMD_MODE_SENSE) {
40576799Sjd218194 headerp = (struct mode_header *)sense_data;
40586799Sjd218194 headerp->length = MODE_HEADER_LENGTH + pages_size -
40596799Sjd218194 sizeof (headerp->length);
40606799Sjd218194 headerp->bdesc_length = 0;
40616799Sjd218194 next_page = sense_data + sizeof (struct mode_header);
40626799Sjd218194 } else {
40637100Spl196000 g1_headerp = (void *)sense_data;
40647000Sjd218194 g1_headerp->length = BE_16(MODE_HEADER_LENGTH_G1 + pages_size -
40657000Sjd218194 sizeof (g1_headerp->length));
40666799Sjd218194 g1_headerp->bdesc_length = 0;
40676799Sjd218194 next_page = sense_data + sizeof (struct mode_header_g1);
40686799Sjd218194 }
40696799Sjd218194
40706799Sjd218194 if (unsupport_page)
40716799Sjd218194 goto finish;
40726799Sjd218194
40736799Sjd218194 if (pagecode == SD_MODE_SENSE_PAGE3_CODE ||
40746799Sjd218194 pagecode == MODEPAGE_ALLPAGES) {
40756799Sjd218194 /* SBC-3 7.1.3.3 Format device page */
40766799Sjd218194 struct mode_format *page3p;
40776799Sjd218194
40787100Spl196000 page3p = (void *)next_page;
40795678Spl196000 page3p->mode_page.code = SD_MODE_SENSE_PAGE3_CODE;
40805678Spl196000 page3p->mode_page.length = sizeof (struct mode_format);
40815678Spl196000 page3p->data_bytes_sect = BE_16(AAC_SECTOR_SIZE);
40825678Spl196000 page3p->sect_track = BE_16(AAC_SECTORS_PER_TRACK);
40836799Sjd218194
40846799Sjd218194 next_page += sizeof (struct mode_format);
40856799Sjd218194 }
40866799Sjd218194
40876799Sjd218194 if (pagecode == SD_MODE_SENSE_PAGE4_CODE ||
40886799Sjd218194 pagecode == MODEPAGE_ALLPAGES) {
40896799Sjd218194 /* SBC-3 7.1.3.8 Rigid disk device geometry page */
40906799Sjd218194 struct mode_geometry *page4p;
40916799Sjd218194
40927100Spl196000 page4p = (void *)next_page;
40935678Spl196000 page4p->mode_page.code = SD_MODE_SENSE_PAGE4_CODE;
40945678Spl196000 page4p->mode_page.length = sizeof (struct mode_geometry);
40955678Spl196000 page4p->heads = AAC_NUMBER_OF_HEADS;
40965678Spl196000 page4p->rpm = BE_16(AAC_ROTATION_SPEED);
40975678Spl196000 ncyl = capacity / (AAC_NUMBER_OF_HEADS * AAC_SECTORS_PER_TRACK);
40985678Spl196000 page4p->cyl_lb = ncyl & 0xff;
40995678Spl196000 page4p->cyl_mb = (ncyl >> 8) & 0xff;
41005678Spl196000 page4p->cyl_ub = (ncyl >> 16) & 0xff;
41016799Sjd218194
41026799Sjd218194 next_page += sizeof (struct mode_geometry);
41036799Sjd218194 }
41046799Sjd218194
41056799Sjd218194 if ((pagecode == MODEPAGE_CTRL_MODE || pagecode == MODEPAGE_ALLPAGES) &&
41066799Sjd218194 softs->flags & AAC_FLAGS_LBA_64BIT) {
41076799Sjd218194 /* 64-bit LBA need large sense data */
41086799Sjd218194 struct mode_control_scsi3 *mctl;
41096799Sjd218194
41107100Spl196000 mctl = (void *)next_page;
41116799Sjd218194 mctl->mode_page.code = MODEPAGE_CTRL_MODE;
41126799Sjd218194 mctl->mode_page.length =
41136799Sjd218194 sizeof (struct mode_control_scsi3) -
41146799Sjd218194 sizeof (struct mode_page);
41156799Sjd218194 mctl->d_sense = 1;
41166799Sjd218194 }
41176799Sjd218194
41186799Sjd218194 finish:
41196799Sjd218194 /* copyout the valid data. */
41206799Sjd218194 bcopy(sense_data, bp->b_un.b_addr, min(sdata_size, bp->b_bcount));
41216799Sjd218194 kmem_free(sense_data, sdata_size);
41225678Spl196000 }
41235678Spl196000
41247567SXin.Chen@Sun.COM static int
aac_name_node(dev_info_t * dip,char * name,int len)41257567SXin.Chen@Sun.COM aac_name_node(dev_info_t *dip, char *name, int len)
41267567SXin.Chen@Sun.COM {
41277567SXin.Chen@Sun.COM int tgt, lun;
41287567SXin.Chen@Sun.COM
41297567SXin.Chen@Sun.COM tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
41307567SXin.Chen@Sun.COM DDI_PROP_DONTPASS, "target", -1);
41317567SXin.Chen@Sun.COM if (tgt == -1)
41327567SXin.Chen@Sun.COM return (DDI_FAILURE);
41337567SXin.Chen@Sun.COM lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
41347567SXin.Chen@Sun.COM DDI_PROP_DONTPASS, "lun", -1);
41357567SXin.Chen@Sun.COM if (lun == -1)
41367567SXin.Chen@Sun.COM return (DDI_FAILURE);
41377567SXin.Chen@Sun.COM
41387567SXin.Chen@Sun.COM (void) snprintf(name, len, "%x,%x", tgt, lun);
41397567SXin.Chen@Sun.COM return (DDI_SUCCESS);
41407567SXin.Chen@Sun.COM }
41417567SXin.Chen@Sun.COM
41425678Spl196000 /*ARGSUSED*/
41435678Spl196000 static int
aac_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * tran,struct scsi_device * sd)41445678Spl196000 aac_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
41455678Spl196000 scsi_hba_tran_t *tran, struct scsi_device *sd)
41465678Spl196000 {
41475678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
41485678Spl196000 #if defined(DEBUG) || defined(__lock_lint)
41495678Spl196000 int ctl = ddi_get_instance(softs->devinfo_p);
41505678Spl196000 #endif
41517567SXin.Chen@Sun.COM uint16_t tgt = sd->sd_address.a_target;
41527567SXin.Chen@Sun.COM uint8_t lun = sd->sd_address.a_lun;
41537567SXin.Chen@Sun.COM struct aac_device *dvp;
41545678Spl196000
41555678Spl196000 DBCALLED(softs, 2);
41565678Spl196000
41577567SXin.Chen@Sun.COM if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
41587567SXin.Chen@Sun.COM /*
41597567SXin.Chen@Sun.COM * If no persistent node exist, we don't allow .conf node
41607567SXin.Chen@Sun.COM * to be created.
41617567SXin.Chen@Sun.COM */
41627567SXin.Chen@Sun.COM if (aac_find_child(softs, tgt, lun) != NULL) {
41637567SXin.Chen@Sun.COM if (ndi_merge_node(tgt_dip, aac_name_node) !=
41647567SXin.Chen@Sun.COM DDI_SUCCESS)
41657567SXin.Chen@Sun.COM /* Create this .conf node */
41667567SXin.Chen@Sun.COM return (DDI_SUCCESS);
41677567SXin.Chen@Sun.COM }
41685678Spl196000 return (DDI_FAILURE);
41695678Spl196000 }
41705678Spl196000
41715678Spl196000 /*
41727567SXin.Chen@Sun.COM * Only support container/phys. device that has been
41737567SXin.Chen@Sun.COM * detected and valid
41745678Spl196000 */
41755678Spl196000 mutex_enter(&softs->io_lock);
41767567SXin.Chen@Sun.COM if (tgt >= AAC_MAX_DEV(softs)) {
41777567SXin.Chen@Sun.COM AACDB_PRINT_TRAN(softs,
41787567SXin.Chen@Sun.COM "aac_tran_tgt_init: c%dt%dL%d out", ctl, tgt, lun);
41795678Spl196000 mutex_exit(&softs->io_lock);
41805678Spl196000 return (DDI_FAILURE);
41815678Spl196000 }
41827567SXin.Chen@Sun.COM
41837567SXin.Chen@Sun.COM if (tgt < AAC_MAX_LD) {
41847567SXin.Chen@Sun.COM dvp = (struct aac_device *)&softs->containers[tgt];
41857567SXin.Chen@Sun.COM if (lun != 0 || !AAC_DEV_IS_VALID(dvp)) {
41867567SXin.Chen@Sun.COM AACDB_PRINT_TRAN(softs, "aac_tran_tgt_init: c%dt%dL%d",
41877567SXin.Chen@Sun.COM ctl, tgt, lun);
41887567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
41897567SXin.Chen@Sun.COM return (DDI_FAILURE);
41907567SXin.Chen@Sun.COM }
41917567SXin.Chen@Sun.COM /*
41927567SXin.Chen@Sun.COM * Save the tgt_dip for the given target if one doesn't exist
41937567SXin.Chen@Sun.COM * already. Dip's for non-existance tgt's will be cleared in
41947567SXin.Chen@Sun.COM * tgt_free.
41957567SXin.Chen@Sun.COM */
41967567SXin.Chen@Sun.COM if (softs->containers[tgt].dev.dip == NULL &&
41977567SXin.Chen@Sun.COM strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
41987567SXin.Chen@Sun.COM softs->containers[tgt].dev.dip = tgt_dip;
41997567SXin.Chen@Sun.COM } else {
42007567SXin.Chen@Sun.COM dvp = (struct aac_device *)&softs->nondasds[AAC_PD(tgt)];
4201*12408SZhongyan.Gu@Sun.COM /*
4202*12408SZhongyan.Gu@Sun.COM * Save the tgt_dip for the given target if one doesn't exist
4203*12408SZhongyan.Gu@Sun.COM * already. Dip's for non-existance tgt's will be cleared in
4204*12408SZhongyan.Gu@Sun.COM * tgt_free.
4205*12408SZhongyan.Gu@Sun.COM */
4206*12408SZhongyan.Gu@Sun.COM
4207*12408SZhongyan.Gu@Sun.COM if (softs->nondasds[AAC_PD(tgt)].dev.dip == NULL &&
4208*12408SZhongyan.Gu@Sun.COM strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
4209*12408SZhongyan.Gu@Sun.COM softs->nondasds[AAC_PD(tgt)].dev.dip = tgt_dip;
42107567SXin.Chen@Sun.COM }
42117567SXin.Chen@Sun.COM
42128551SPeng.L@Sun.COM if (softs->flags & AAC_FLAGS_BRKUP) {
42138551SPeng.L@Sun.COM if (ndi_prop_update_int(DDI_DEV_T_NONE, tgt_dip,
42148551SPeng.L@Sun.COM "buf_break", 1) != DDI_PROP_SUCCESS) {
42158551SPeng.L@Sun.COM cmn_err(CE_CONT, "unable to create "
42168551SPeng.L@Sun.COM "property for t%dL%d (buf_break)", tgt, lun);
42178551SPeng.L@Sun.COM }
42189106SSrivijitha.Dugganapalli@Sun.COM }
42198551SPeng.L@Sun.COM
42207567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
42217567SXin.Chen@Sun.COM "aac_tran_tgt_init: c%dt%dL%d ok (%s)", ctl, tgt, lun,
42227567SXin.Chen@Sun.COM (dvp->type == AAC_DEV_PD) ? "pd" : "ld");
42237567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
42247567SXin.Chen@Sun.COM return (DDI_SUCCESS);
42257567SXin.Chen@Sun.COM }
42267567SXin.Chen@Sun.COM
42277567SXin.Chen@Sun.COM static void
aac_tran_tgt_free(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)42287567SXin.Chen@Sun.COM aac_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
42297567SXin.Chen@Sun.COM scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
42307567SXin.Chen@Sun.COM {
42317567SXin.Chen@Sun.COM #ifndef __lock_lint
42327567SXin.Chen@Sun.COM _NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran))
42337567SXin.Chen@Sun.COM #endif
42347567SXin.Chen@Sun.COM
42357567SXin.Chen@Sun.COM struct aac_softstate *softs = SD2AAC(sd);
42367567SXin.Chen@Sun.COM int tgt = sd->sd_address.a_target;
42377567SXin.Chen@Sun.COM
42387567SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
42397567SXin.Chen@Sun.COM if (tgt < AAC_MAX_LD) {
42407567SXin.Chen@Sun.COM if (softs->containers[tgt].dev.dip == tgt_dip)
42417567SXin.Chen@Sun.COM softs->containers[tgt].dev.dip = NULL;
42427567SXin.Chen@Sun.COM } else {
4243*12408SZhongyan.Gu@Sun.COM if (softs->nondasds[AAC_PD(tgt)].dev.dip == tgt_dip)
4244*12408SZhongyan.Gu@Sun.COM softs->nondasds[AAC_PD(tgt)].dev.dip = NULL;
42457567SXin.Chen@Sun.COM softs->nondasds[AAC_PD(tgt)].dev.flags &= ~AAC_DFLAG_VALID;
42467567SXin.Chen@Sun.COM }
42477567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
42485678Spl196000 }
42495678Spl196000
42505678Spl196000 /*
42515678Spl196000 * Check if the firmware is Up And Running. If it is in the Kernel Panic
42525678Spl196000 * state, (BlinkLED code + 1) is returned.
42535678Spl196000 * 0 -- firmware up and running
42545678Spl196000 * -1 -- firmware dead
42555678Spl196000 * >0 -- firmware kernel panic
42565678Spl196000 */
42575678Spl196000 static int
aac_check_adapter_health(struct aac_softstate * softs)42585678Spl196000 aac_check_adapter_health(struct aac_softstate *softs)
42595678Spl196000 {
42605678Spl196000 int rval;
42615678Spl196000
42625678Spl196000 rval = PCI_MEM_GET32(softs, AAC_OMR0);
42635678Spl196000
42645678Spl196000 if (rval & AAC_KERNEL_UP_AND_RUNNING) {
42655678Spl196000 rval = 0;
42665678Spl196000 } else if (rval & AAC_KERNEL_PANIC) {
42675678Spl196000 cmn_err(CE_WARN, "firmware panic");
42685678Spl196000 rval = ((rval >> 16) & 0xff) + 1; /* avoid 0 as return value */
42695678Spl196000 } else {
42705678Spl196000 cmn_err(CE_WARN, "firmware dead");
42715678Spl196000 rval = -1;
42725678Spl196000 }
42735678Spl196000 return (rval);
42745678Spl196000 }
42755678Spl196000
42765678Spl196000 static void
aac_abort_iocmd(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason)42775678Spl196000 aac_abort_iocmd(struct aac_softstate *softs, struct aac_cmd *acp,
42785678Spl196000 uchar_t reason)
42795678Spl196000 {
42805678Spl196000 acp->flags |= AAC_CMD_ABORT;
42815678Spl196000
42825678Spl196000 if (acp->pkt) {
42837567SXin.Chen@Sun.COM if (acp->slotp) { /* outstanding cmd */
42847567SXin.Chen@Sun.COM acp->pkt->pkt_state |= STATE_GOT_STATUS;
42857567SXin.Chen@Sun.COM }
42865678Spl196000
42875678Spl196000 switch (reason) {
42885678Spl196000 case CMD_TIMEOUT:
42897567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "CMD_TIMEOUT: acp=0x%p",
42907567SXin.Chen@Sun.COM acp);
42915678Spl196000 aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
42925678Spl196000 STAT_TIMEOUT | STAT_BUS_RESET);
42935678Spl196000 break;
42945678Spl196000 case CMD_RESET:
42955678Spl196000 /* aac support only RESET_ALL */
42967567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "CMD_RESET: acp=0x%p", acp);
42975678Spl196000 aac_set_pkt_reason(softs, acp, CMD_RESET,
42985678Spl196000 STAT_BUS_RESET);
42995678Spl196000 break;
43005678Spl196000 case CMD_ABORTED:
43017567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "CMD_ABORTED: acp=0x%p",
43027567SXin.Chen@Sun.COM acp);
43035678Spl196000 aac_set_pkt_reason(softs, acp, CMD_ABORTED,
43045678Spl196000 STAT_ABORTED);
43055678Spl196000 break;
43065678Spl196000 }
43075678Spl196000 }
43085678Spl196000 aac_end_io(softs, acp);
43095678Spl196000 }
43105678Spl196000
43115678Spl196000 /*
43125678Spl196000 * Abort all the pending commands of type iocmd or just the command pkt
43135678Spl196000 * corresponding to pkt
43145678Spl196000 */
43155678Spl196000 static void
aac_abort_iocmds(struct aac_softstate * softs,int iocmd,struct scsi_pkt * pkt,int reason)43165678Spl196000 aac_abort_iocmds(struct aac_softstate *softs, int iocmd, struct scsi_pkt *pkt,
43175678Spl196000 int reason)
43185678Spl196000 {
43195678Spl196000 struct aac_cmd *ac_arg, *acp;
43205678Spl196000 int i;
43215678Spl196000
43225678Spl196000 if (pkt == NULL) {
43235678Spl196000 ac_arg = NULL;
43245678Spl196000 } else {
43255678Spl196000 ac_arg = PKT2AC(pkt);
43265678Spl196000 iocmd = (ac_arg->flags & AAC_CMD_SYNC) ?
43275678Spl196000 AAC_IOCMD_SYNC : AAC_IOCMD_ASYNC;
43285678Spl196000 }
43295678Spl196000
43305678Spl196000 /*
43315678Spl196000 * a) outstanding commands on the controller
43325678Spl196000 * Note: should abort outstanding commands only after one
43335678Spl196000 * IOP reset has been done.
43345678Spl196000 */
43355678Spl196000 if (iocmd & AAC_IOCMD_OUTSTANDING) {
43365678Spl196000 struct aac_cmd *acp;
43375678Spl196000
43385678Spl196000 for (i = 0; i < AAC_MAX_LD; i++) {
43397567SXin.Chen@Sun.COM if (AAC_DEV_IS_VALID(&softs->containers[i].dev))
43405678Spl196000 softs->containers[i].reset = 1;
43415678Spl196000 }
43425678Spl196000 while ((acp = softs->q_busy.q_head) != NULL)
43435678Spl196000 aac_abort_iocmd(softs, acp, reason);
43445678Spl196000 }
43455678Spl196000
43465678Spl196000 /* b) commands in the waiting queues */
43475678Spl196000 for (i = 0; i < AAC_CMDQ_NUM; i++) {
43485678Spl196000 if (iocmd & (1 << i)) {
43495678Spl196000 if (ac_arg) {
43505678Spl196000 aac_abort_iocmd(softs, ac_arg, reason);
43515678Spl196000 } else {
43525678Spl196000 while ((acp = softs->q_wait[i].q_head) != NULL)
43535678Spl196000 aac_abort_iocmd(softs, acp, reason);
43545678Spl196000 }
43555678Spl196000 }
43565678Spl196000 }
43575678Spl196000 }
43585678Spl196000
43595678Spl196000 /*
43605678Spl196000 * The draining thread is shared among quiesce threads. It terminates
43615678Spl196000 * when the adapter is quiesced or stopped by aac_stop_drain().
43625678Spl196000 */
43635678Spl196000 static void
aac_check_drain(void * arg)43645678Spl196000 aac_check_drain(void *arg)
43655678Spl196000 {
43665678Spl196000 struct aac_softstate *softs = arg;
43675678Spl196000
43685678Spl196000 mutex_enter(&softs->io_lock);
43695678Spl196000 if (softs->ndrains) {
43707567SXin.Chen@Sun.COM softs->drain_timeid = 0;
43715678Spl196000 /*
43725678Spl196000 * If both ASYNC and SYNC bus throttle are held,
43735678Spl196000 * wake up threads only when both are drained out.
43745678Spl196000 */
43755678Spl196000 if ((softs->bus_throttle[AAC_CMDQ_ASYNC] > 0 ||
43765678Spl196000 softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) &&
43775678Spl196000 (softs->bus_throttle[AAC_CMDQ_SYNC] > 0 ||
43785678Spl196000 softs->bus_ncmds[AAC_CMDQ_SYNC] == 0))
43795678Spl196000 cv_broadcast(&softs->drain_cv);
43805678Spl196000 else
43815678Spl196000 softs->drain_timeid = timeout(aac_check_drain, softs,
43825678Spl196000 AAC_QUIESCE_TICK * drv_usectohz(1000000));
43835678Spl196000 }
43845678Spl196000 mutex_exit(&softs->io_lock);
43855678Spl196000 }
43865678Spl196000
43875678Spl196000 /*
43885678Spl196000 * If not draining the outstanding cmds, drain them. Otherwise,
43895678Spl196000 * only update ndrains.
43905678Spl196000 */
43915678Spl196000 static void
aac_start_drain(struct aac_softstate * softs)43925678Spl196000 aac_start_drain(struct aac_softstate *softs)
43935678Spl196000 {
43945678Spl196000 if (softs->ndrains == 0) {
43957567SXin.Chen@Sun.COM ASSERT(softs->drain_timeid == 0);
43965678Spl196000 softs->drain_timeid = timeout(aac_check_drain, softs,
43975678Spl196000 AAC_QUIESCE_TICK * drv_usectohz(1000000));
43985678Spl196000 }
43995678Spl196000 softs->ndrains++;
44005678Spl196000 }
44015678Spl196000
44025678Spl196000 /*
44035678Spl196000 * Stop the draining thread when no other threads use it any longer.
44045678Spl196000 * Side effect: io_lock may be released in the middle.
44055678Spl196000 */
44065678Spl196000 static void
aac_stop_drain(struct aac_softstate * softs)44075678Spl196000 aac_stop_drain(struct aac_softstate *softs)
44085678Spl196000 {
44095678Spl196000 softs->ndrains--;
44105678Spl196000 if (softs->ndrains == 0) {
44115678Spl196000 if (softs->drain_timeid != 0) {
44125678Spl196000 timeout_id_t tid = softs->drain_timeid;
44135678Spl196000
44145678Spl196000 softs->drain_timeid = 0;
44155678Spl196000 mutex_exit(&softs->io_lock);
44165678Spl196000 (void) untimeout(tid);
44175678Spl196000 mutex_enter(&softs->io_lock);
44185678Spl196000 }
44195678Spl196000 }
44205678Spl196000 }
44215678Spl196000
44225678Spl196000 /*
44235678Spl196000 * The following function comes from Adaptec:
44245678Spl196000 *
44255678Spl196000 * Once do an IOP reset, basically the driver have to re-initialize the card
44265678Spl196000 * as if up from a cold boot, and the driver is responsible for any IO that
44275678Spl196000 * is outstanding to the adapter at the time of the IOP RESET. And prepare
44285678Spl196000 * for IOP RESET by making the init code modular with the ability to call it
44295678Spl196000 * from multiple places.
44305678Spl196000 */
44315678Spl196000 static int
aac_reset_adapter(struct aac_softstate * softs)44325678Spl196000 aac_reset_adapter(struct aac_softstate *softs)
44335678Spl196000 {
44345678Spl196000 int health;
44355678Spl196000 uint32_t status;
44367567SXin.Chen@Sun.COM int rval = AAC_IOP_RESET_FAILED;
44375678Spl196000
44385678Spl196000 DBCALLED(softs, 1);
44395678Spl196000
44405678Spl196000 ASSERT(softs->state & AAC_STATE_RESET);
44415678Spl196000
44425678Spl196000 ddi_fm_acc_err_clear(softs->pci_mem_handle, DDI_FME_VER0);
44435678Spl196000 /* Disable interrupt */
44445678Spl196000 AAC_DISABLE_INTR(softs);
44455678Spl196000
44465678Spl196000 health = aac_check_adapter_health(softs);
44475678Spl196000 if (health == -1) {
44485678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
44495678Spl196000 goto finish;
44505678Spl196000 }
44515678Spl196000 if (health == 0) /* flush drives if possible */
44525678Spl196000 (void) aac_shutdown(softs);
44535678Spl196000
44545678Spl196000 /* Execute IOP reset */
44555678Spl196000 if ((aac_sync_mbcommand(softs, AAC_IOP_RESET, 0, 0, 0, 0,
44565678Spl196000 &status)) != AACOK) {
445711348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
44585678Spl196000 struct aac_fib *fibp;
44595678Spl196000 struct aac_pause_command *pc;
44605678Spl196000
44615678Spl196000 if ((status & 0xf) == 0xf) {
44625678Spl196000 uint32_t wait_count;
44635678Spl196000
44645678Spl196000 /*
44655678Spl196000 * Sunrise Lake has dual cores and we must drag the
44665678Spl196000 * other core with us to reset simultaneously. There
44675678Spl196000 * are 2 bits in the Inbound Reset Control and Status
44685678Spl196000 * Register (offset 0x38) of the Sunrise Lake to reset
44695678Spl196000 * the chip without clearing out the PCI configuration
44705678Spl196000 * info (COMMAND & BARS).
44715678Spl196000 */
44725678Spl196000 PCI_MEM_PUT32(softs, AAC_IRCSR, AAC_IRCSR_CORES_RST);
44735678Spl196000
44745678Spl196000 /*
44755678Spl196000 * We need to wait for 5 seconds before accessing the MU
44765678Spl196000 * again 10000 * 100us = 1000,000us = 1000ms = 1s
44775678Spl196000 */
44785678Spl196000 wait_count = 5 * 10000;
44795678Spl196000 while (wait_count) {
44805678Spl196000 drv_usecwait(100); /* delay 100 microseconds */
44815678Spl196000 wait_count--;
44825678Spl196000 }
44835678Spl196000 } else {
44845678Spl196000 if (status == SRB_STATUS_INVALID_REQUEST)
44855678Spl196000 cmn_err(CE_WARN, "!IOP_RESET not supported");
44865678Spl196000 else /* probably timeout */
44875678Spl196000 cmn_err(CE_WARN, "!IOP_RESET failed");
44885678Spl196000
44895678Spl196000 /* Unwind aac_shutdown() */
449011348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
449111348SZhongyan.Gu@Sun.COM acc = softs->sync_ac.slotp->fib_acc_handle;
449211348SZhongyan.Gu@Sun.COM
449311348SZhongyan.Gu@Sun.COM fibp = softs->sync_ac.slotp->fibp;
44945678Spl196000 pc = (struct aac_pause_command *)&fibp->data[0];
44955678Spl196000
44965678Spl196000 bzero(pc, sizeof (*pc));
44975678Spl196000 ddi_put32(acc, &pc->Command, VM_ContainerConfig);
44985678Spl196000 ddi_put32(acc, &pc->Type, CT_PAUSE_IO);
44995678Spl196000 ddi_put32(acc, &pc->Timeout, 1);
45005678Spl196000 ddi_put32(acc, &pc->Min, 1);
45015678Spl196000 ddi_put32(acc, &pc->NoRescan, 1);
45025678Spl196000
45035678Spl196000 (void) aac_sync_fib(softs, ContainerCommand,
45045678Spl196000 AAC_FIB_SIZEOF(struct aac_pause_command));
450511348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, &softs->sync_ac);
45065678Spl196000
45077567SXin.Chen@Sun.COM if (aac_check_adapter_health(softs) != 0)
45087567SXin.Chen@Sun.COM ddi_fm_service_impact(softs->devinfo_p,
45097567SXin.Chen@Sun.COM DDI_SERVICE_LOST);
45107567SXin.Chen@Sun.COM else
45117567SXin.Chen@Sun.COM /*
45127567SXin.Chen@Sun.COM * IOP reset not supported or IOP not reseted
45137567SXin.Chen@Sun.COM */
45147567SXin.Chen@Sun.COM rval = AAC_IOP_RESET_ABNORMAL;
45155678Spl196000 goto finish;
45165678Spl196000 }
45175678Spl196000 }
45185678Spl196000
45195678Spl196000 /*
45205678Spl196000 * Re-read and renegotiate the FIB parameters, as one of the actions
45215678Spl196000 * that can result from an IOP reset is the running of a new firmware
45225678Spl196000 * image.
45235678Spl196000 */
45245678Spl196000 if (aac_common_attach(softs) != AACOK)
45255678Spl196000 goto finish;
45265678Spl196000
45277567SXin.Chen@Sun.COM rval = AAC_IOP_RESET_SUCCEED;
45285678Spl196000
45295678Spl196000 finish:
45305678Spl196000 AAC_ENABLE_INTR(softs);
45315678Spl196000 return (rval);
45325678Spl196000 }
45335678Spl196000
45345678Spl196000 static void
aac_set_throttle(struct aac_softstate * softs,struct aac_device * dvp,int q,int throttle)45357567SXin.Chen@Sun.COM aac_set_throttle(struct aac_softstate *softs, struct aac_device *dvp, int q,
45365678Spl196000 int throttle)
45375678Spl196000 {
45385678Spl196000 /*
45395678Spl196000 * If the bus is draining/quiesced, no changes to the throttles
45405678Spl196000 * are allowed. All throttles should have been set to 0.
45415678Spl196000 */
45425678Spl196000 if ((softs->state & AAC_STATE_QUIESCED) || softs->ndrains)
45435678Spl196000 return;
45445678Spl196000 dvp->throttle[q] = throttle;
45455678Spl196000 }
45465678Spl196000
45475678Spl196000 static void
aac_hold_bus(struct aac_softstate * softs,int iocmds)45485678Spl196000 aac_hold_bus(struct aac_softstate *softs, int iocmds)
45495678Spl196000 {
45505678Spl196000 int i, q;
45515678Spl196000
45525678Spl196000 /* Hold bus by holding every device on the bus */
45535678Spl196000 for (q = 0; q < AAC_CMDQ_NUM; q++) {
45545678Spl196000 if (iocmds & (1 << q)) {
45555678Spl196000 softs->bus_throttle[q] = 0;
45565678Spl196000 for (i = 0; i < AAC_MAX_LD; i++)
45577567SXin.Chen@Sun.COM aac_set_throttle(softs,
45587567SXin.Chen@Sun.COM &softs->containers[i].dev, q, 0);
45597567SXin.Chen@Sun.COM for (i = 0; i < AAC_MAX_PD(softs); i++)
45607567SXin.Chen@Sun.COM aac_set_throttle(softs,
45617567SXin.Chen@Sun.COM &softs->nondasds[i].dev, q, 0);
45625678Spl196000 }
45635678Spl196000 }
45645678Spl196000 }
45655678Spl196000
45665678Spl196000 static void
aac_unhold_bus(struct aac_softstate * softs,int iocmds)45675678Spl196000 aac_unhold_bus(struct aac_softstate *softs, int iocmds)
45685678Spl196000 {
456911348SZhongyan.Gu@Sun.COM int i, q, max_throttle;
45705678Spl196000
45715678Spl196000 for (q = 0; q < AAC_CMDQ_NUM; q++) {
45725678Spl196000 if (iocmds & (1 << q)) {
45735678Spl196000 /*
45745678Spl196000 * Should not unhold AAC_IOCMD_ASYNC bus, if it has been
45755678Spl196000 * quiesced or being drained by possibly some quiesce
45765678Spl196000 * threads.
45775678Spl196000 */
45785678Spl196000 if (q == AAC_CMDQ_ASYNC && ((softs->state &
45795678Spl196000 AAC_STATE_QUIESCED) || softs->ndrains))
45805678Spl196000 continue;
458111348SZhongyan.Gu@Sun.COM if (q == AAC_CMDQ_ASYNC)
458211348SZhongyan.Gu@Sun.COM max_throttle = softs->total_slots -
458311348SZhongyan.Gu@Sun.COM AAC_MGT_SLOT_NUM;
458411348SZhongyan.Gu@Sun.COM else
458511348SZhongyan.Gu@Sun.COM max_throttle = softs->total_slots - 1;
458611348SZhongyan.Gu@Sun.COM softs->bus_throttle[q] = max_throttle;
45875678Spl196000 for (i = 0; i < AAC_MAX_LD; i++)
45887567SXin.Chen@Sun.COM aac_set_throttle(softs,
45897567SXin.Chen@Sun.COM &softs->containers[i].dev,
459011348SZhongyan.Gu@Sun.COM q, max_throttle);
45917567SXin.Chen@Sun.COM for (i = 0; i < AAC_MAX_PD(softs); i++)
45927567SXin.Chen@Sun.COM aac_set_throttle(softs, &softs->nondasds[i].dev,
459311348SZhongyan.Gu@Sun.COM q, max_throttle);
45945678Spl196000 }
45955678Spl196000 }
45965678Spl196000 }
45975678Spl196000
45985678Spl196000 static int
aac_do_reset(struct aac_softstate * softs)45995678Spl196000 aac_do_reset(struct aac_softstate *softs)
46005678Spl196000 {
46015678Spl196000 int health;
46025678Spl196000 int rval;
46035678Spl196000
46045678Spl196000 softs->state |= AAC_STATE_RESET;
46055678Spl196000 health = aac_check_adapter_health(softs);
46065678Spl196000
46075678Spl196000 /*
46085678Spl196000 * Hold off new io commands and wait all outstanding io
46095678Spl196000 * commands to complete.
46105678Spl196000 */
46117567SXin.Chen@Sun.COM if (health == 0) {
46127567SXin.Chen@Sun.COM int sync_cmds = softs->bus_ncmds[AAC_CMDQ_SYNC];
46137567SXin.Chen@Sun.COM int async_cmds = softs->bus_ncmds[AAC_CMDQ_ASYNC];
46147567SXin.Chen@Sun.COM
46157567SXin.Chen@Sun.COM if (sync_cmds == 0 && async_cmds == 0) {
46167567SXin.Chen@Sun.COM rval = AAC_IOP_RESET_SUCCEED;
46177567SXin.Chen@Sun.COM goto finish;
46187567SXin.Chen@Sun.COM }
46195678Spl196000 /*
46205678Spl196000 * Give the adapter up to AAC_QUIESCE_TIMEOUT more seconds
46215678Spl196000 * to complete the outstanding io commands
46225678Spl196000 */
46235678Spl196000 int timeout = AAC_QUIESCE_TIMEOUT * 1000 * 10;
46245678Spl196000 int (*intr_handler)(struct aac_softstate *);
46255678Spl196000
46265678Spl196000 aac_hold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
46275678Spl196000 /*
46285678Spl196000 * Poll the adapter by ourselves in case interrupt is disabled
46295678Spl196000 * and to avoid releasing the io_lock.
46305678Spl196000 */
46315678Spl196000 intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
46325678Spl196000 aac_process_intr_new : aac_process_intr_old;
46335678Spl196000 while ((softs->bus_ncmds[AAC_CMDQ_SYNC] ||
46345678Spl196000 softs->bus_ncmds[AAC_CMDQ_ASYNC]) && timeout) {
46355678Spl196000 drv_usecwait(100);
46365678Spl196000 (void) intr_handler(softs);
46375678Spl196000 timeout--;
46385678Spl196000 }
46395678Spl196000 aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
46407567SXin.Chen@Sun.COM
46417567SXin.Chen@Sun.COM if (softs->bus_ncmds[AAC_CMDQ_SYNC] == 0 &&
46427567SXin.Chen@Sun.COM softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) {
46437567SXin.Chen@Sun.COM /* Cmds drained out */
46447567SXin.Chen@Sun.COM rval = AAC_IOP_RESET_SUCCEED;
46457567SXin.Chen@Sun.COM goto finish;
46467567SXin.Chen@Sun.COM } else if (softs->bus_ncmds[AAC_CMDQ_SYNC] < sync_cmds ||
46477567SXin.Chen@Sun.COM softs->bus_ncmds[AAC_CMDQ_ASYNC] < async_cmds) {
46487567SXin.Chen@Sun.COM /* Cmds not drained out, adapter overloaded */
46497567SXin.Chen@Sun.COM rval = AAC_IOP_RESET_ABNORMAL;
46507567SXin.Chen@Sun.COM goto finish;
46517567SXin.Chen@Sun.COM }
46525678Spl196000 }
46535678Spl196000
46545678Spl196000 /*
46557567SXin.Chen@Sun.COM * If a longer waiting time still can't drain any outstanding io
46565678Spl196000 * commands, do IOP reset.
46575678Spl196000 */
46587567SXin.Chen@Sun.COM if ((rval = aac_reset_adapter(softs)) == AAC_IOP_RESET_FAILED)
46597567SXin.Chen@Sun.COM softs->state |= AAC_STATE_DEAD;
46607567SXin.Chen@Sun.COM
46617567SXin.Chen@Sun.COM finish:
46625678Spl196000 softs->state &= ~AAC_STATE_RESET;
46635678Spl196000 return (rval);
46645678Spl196000 }
46655678Spl196000
46665678Spl196000 static int
aac_tran_reset(struct scsi_address * ap,int level)46675678Spl196000 aac_tran_reset(struct scsi_address *ap, int level)
46685678Spl196000 {
46695678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
46705678Spl196000 int rval;
46715678Spl196000
46725678Spl196000 DBCALLED(softs, 1);
46735678Spl196000
46745678Spl196000 if (level != RESET_ALL) {
46755678Spl196000 cmn_err(CE_NOTE, "!reset target/lun not supported");
46765678Spl196000 return (0);
46775678Spl196000 }
46785678Spl196000
46795678Spl196000 mutex_enter(&softs->io_lock);
46807567SXin.Chen@Sun.COM switch (rval = aac_do_reset(softs)) {
46817567SXin.Chen@Sun.COM case AAC_IOP_RESET_SUCCEED:
46825678Spl196000 aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING | AAC_IOCMD_ASYNC,
46835678Spl196000 NULL, CMD_RESET);
46845678Spl196000 aac_start_waiting_io(softs);
46857567SXin.Chen@Sun.COM break;
46867567SXin.Chen@Sun.COM case AAC_IOP_RESET_FAILED:
46877567SXin.Chen@Sun.COM /* Abort IOCTL cmds when adapter is dead */
46885678Spl196000 aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_RESET);
46897567SXin.Chen@Sun.COM break;
46907567SXin.Chen@Sun.COM case AAC_IOP_RESET_ABNORMAL:
46917567SXin.Chen@Sun.COM aac_start_waiting_io(softs);
46925678Spl196000 }
46935678Spl196000 mutex_exit(&softs->io_lock);
46945678Spl196000
46955678Spl196000 aac_drain_comp_q(softs);
46967567SXin.Chen@Sun.COM return (rval == 0);
46975678Spl196000 }
46985678Spl196000
46995678Spl196000 static int
aac_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)47005678Spl196000 aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
47015678Spl196000 {
47025678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
47035678Spl196000
47045678Spl196000 DBCALLED(softs, 1);
47055678Spl196000
47065678Spl196000 mutex_enter(&softs->io_lock);
47075678Spl196000 aac_abort_iocmds(softs, 0, pkt, CMD_ABORTED);
47085678Spl196000 mutex_exit(&softs->io_lock);
47095678Spl196000
47105678Spl196000 aac_drain_comp_q(softs);
47115678Spl196000 return (1);
47125678Spl196000 }
47135678Spl196000
47145678Spl196000 void
aac_free_dmamap(struct aac_cmd * acp)47155678Spl196000 aac_free_dmamap(struct aac_cmd *acp)
47165678Spl196000 {
47175678Spl196000 /* Free dma mapping */
47185678Spl196000 if (acp->flags & AAC_CMD_DMA_VALID) {
47195678Spl196000 ASSERT(acp->buf_dma_handle);
47205678Spl196000 (void) ddi_dma_unbind_handle(acp->buf_dma_handle);
47215678Spl196000 acp->flags &= ~AAC_CMD_DMA_VALID;
47225678Spl196000 }
47235678Spl196000
47245678Spl196000 if (acp->abp != NULL) { /* free non-aligned buf DMA */
47255678Spl196000 ASSERT(acp->buf_dma_handle);
47265678Spl196000 if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
47275678Spl196000 ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
47285678Spl196000 (uint8_t *)acp->abp, acp->bp->b_bcount,
47295678Spl196000 DDI_DEV_AUTOINCR);
47305678Spl196000 ddi_dma_mem_free(&acp->abh);
47315678Spl196000 acp->abp = NULL;
47325678Spl196000 }
47335678Spl196000
47345678Spl196000 if (acp->buf_dma_handle) {
47355678Spl196000 ddi_dma_free_handle(&acp->buf_dma_handle);
47365678Spl196000 acp->buf_dma_handle = NULL;
47375678Spl196000 }
47385678Spl196000 }
47395678Spl196000
47405678Spl196000 static void
aac_unknown_scmd(struct aac_softstate * softs,struct aac_cmd * acp)47415678Spl196000 aac_unknown_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
47425678Spl196000 {
47435678Spl196000 AACDB_PRINT(softs, CE_CONT, "SCMD 0x%x not supported",
47447100Spl196000 ((union scsi_cdb *)(void *)acp->pkt->pkt_cdbp)->scc_cmd);
47455678Spl196000 aac_free_dmamap(acp);
47465678Spl196000 aac_set_arq_data(acp->pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
47475678Spl196000 aac_soft_callback(softs, acp);
47485678Spl196000 }
47495678Spl196000
47505678Spl196000 /*
47515678Spl196000 * Handle command to logical device
47525678Spl196000 */
47535678Spl196000 static int
aac_tran_start_ld(struct aac_softstate * softs,struct aac_cmd * acp)47545678Spl196000 aac_tran_start_ld(struct aac_softstate *softs, struct aac_cmd *acp)
47555678Spl196000 {
47565678Spl196000 struct aac_container *dvp;
47575678Spl196000 struct scsi_pkt *pkt;
47585678Spl196000 union scsi_cdb *cdbp;
47595678Spl196000 struct buf *bp;
47605678Spl196000 int rval;
47615678Spl196000
47627567SXin.Chen@Sun.COM dvp = (struct aac_container *)acp->dvp;
47635678Spl196000 pkt = acp->pkt;
47647100Spl196000 cdbp = (void *)pkt->pkt_cdbp;
47655678Spl196000 bp = acp->bp;
47665678Spl196000
47675678Spl196000 switch (cdbp->scc_cmd) {
47685678Spl196000 case SCMD_INQUIRY: /* inquiry */
47695678Spl196000 aac_free_dmamap(acp);
47705678Spl196000 aac_inquiry(softs, pkt, cdbp, bp);
47715678Spl196000 aac_soft_callback(softs, acp);
47725678Spl196000 rval = TRAN_ACCEPT;
47735678Spl196000 break;
47745678Spl196000
47755678Spl196000 case SCMD_READ_CAPACITY: /* read capacity */
47765678Spl196000 if (bp && bp->b_un.b_addr && bp->b_bcount) {
47775678Spl196000 struct scsi_capacity cap;
47785678Spl196000 uint64_t last_lba;
47795678Spl196000
47805678Spl196000 /* check 64-bit LBA */
47815678Spl196000 last_lba = dvp->size - 1;
47825678Spl196000 if (last_lba > 0xffffffffull) {
47835678Spl196000 cap.capacity = 0xfffffffful;
47845678Spl196000 } else {
47855678Spl196000 cap.capacity = BE_32(last_lba);
47865678Spl196000 }
47875678Spl196000 cap.lbasize = BE_32(AAC_SECTOR_SIZE);
47885678Spl196000
47895678Spl196000 aac_free_dmamap(acp);
47905678Spl196000 if (bp->b_flags & (B_PHYS|B_PAGEIO))
47915678Spl196000 bp_mapin(bp);
47926799Sjd218194 bcopy(&cap, bp->b_un.b_addr, min(bp->b_bcount, 8));
47935678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
47945678Spl196000 }
47955678Spl196000 aac_soft_callback(softs, acp);
47965678Spl196000 rval = TRAN_ACCEPT;
47975678Spl196000 break;
47985678Spl196000
47995678Spl196000 case SCMD_SVC_ACTION_IN_G4: /* read capacity 16 */
48005678Spl196000 /* Check if containers need 64-bit LBA support */
48015678Spl196000 if (cdbp->cdb_opaque[1] == SSVC_ACTION_READ_CAPACITY_G4) {
48025678Spl196000 if (bp && bp->b_un.b_addr && bp->b_bcount) {
48035678Spl196000 struct scsi_capacity_16 cap16;
48045678Spl196000 int cap_len = sizeof (struct scsi_capacity_16);
48055678Spl196000
48065678Spl196000 bzero(&cap16, cap_len);
48077000Sjd218194 cap16.sc_capacity = BE_64(dvp->size - 1);
48085678Spl196000 cap16.sc_lbasize = BE_32(AAC_SECTOR_SIZE);
48095678Spl196000
48105678Spl196000 aac_free_dmamap(acp);
48115678Spl196000 if (bp->b_flags & (B_PHYS | B_PAGEIO))
48125678Spl196000 bp_mapin(bp);
48136799Sjd218194 bcopy(&cap16, bp->b_un.b_addr,
48146799Sjd218194 min(bp->b_bcount, cap_len));
48155678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
48165678Spl196000 }
48175678Spl196000 aac_soft_callback(softs, acp);
48185678Spl196000 } else {
48195678Spl196000 aac_unknown_scmd(softs, acp);
48205678Spl196000 }
48215678Spl196000 rval = TRAN_ACCEPT;
48225678Spl196000 break;
48235678Spl196000
48245678Spl196000 case SCMD_READ_G4: /* read_16 */
48255678Spl196000 case SCMD_WRITE_G4: /* write_16 */
48265678Spl196000 if (softs->flags & AAC_FLAGS_RAW_IO) {
48275678Spl196000 /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
48285678Spl196000 acp->blkno = ((uint64_t) \
48295678Spl196000 GETG4ADDR(cdbp) << 32) | \
48305678Spl196000 (uint32_t)GETG4ADDRTL(cdbp);
48315678Spl196000 goto do_io;
48325678Spl196000 }
48335678Spl196000 AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
48345678Spl196000 aac_unknown_scmd(softs, acp);
48355678Spl196000 rval = TRAN_ACCEPT;
48365678Spl196000 break;
48375678Spl196000
48385678Spl196000 case SCMD_READ: /* read_6 */
48395678Spl196000 case SCMD_WRITE: /* write_6 */
48405678Spl196000 acp->blkno = GETG0ADDR(cdbp);
48415678Spl196000 goto do_io;
48425678Spl196000
48437567SXin.Chen@Sun.COM case SCMD_READ_G5: /* read_12 */
48447567SXin.Chen@Sun.COM case SCMD_WRITE_G5: /* write_12 */
48457567SXin.Chen@Sun.COM acp->blkno = GETG5ADDR(cdbp);
48467567SXin.Chen@Sun.COM goto do_io;
48477567SXin.Chen@Sun.COM
48485678Spl196000 case SCMD_READ_G1: /* read_10 */
48495678Spl196000 case SCMD_WRITE_G1: /* write_10 */
48505678Spl196000 acp->blkno = (uint32_t)GETG1ADDR(cdbp);
48515678Spl196000 do_io:
48525678Spl196000 if (acp->flags & AAC_CMD_DMA_VALID) {
48535678Spl196000 uint64_t cnt_size = dvp->size;
48545678Spl196000
48555678Spl196000 /*
48565678Spl196000 * If LBA > array size AND rawio, the
48575678Spl196000 * adapter may hang. So check it before
48585678Spl196000 * sending.
48595678Spl196000 * NOTE: (blkno + blkcnt) may overflow
48605678Spl196000 */
48615678Spl196000 if ((acp->blkno < cnt_size) &&
48625678Spl196000 ((acp->blkno + acp->bcount /
48635678Spl196000 AAC_BLK_SIZE) <= cnt_size)) {
48645678Spl196000 rval = aac_do_io(softs, acp);
48655678Spl196000 } else {
48665678Spl196000 /*
48675678Spl196000 * Request exceeds the capacity of disk,
48685678Spl196000 * set error block number to last LBA
48695678Spl196000 * + 1.
48705678Spl196000 */
48715678Spl196000 aac_set_arq_data(pkt,
48725678Spl196000 KEY_ILLEGAL_REQUEST, 0x21,
48735678Spl196000 0x00, cnt_size);
48745678Spl196000 aac_soft_callback(softs, acp);
48755678Spl196000 rval = TRAN_ACCEPT;
48765678Spl196000 }
48775678Spl196000 } else if (acp->bcount == 0) {
48785678Spl196000 /* For 0 length IO, just return ok */
48795678Spl196000 aac_soft_callback(softs, acp);
48805678Spl196000 rval = TRAN_ACCEPT;
48815678Spl196000 } else {
48825678Spl196000 rval = TRAN_BADPKT;
48835678Spl196000 }
48845678Spl196000 break;
48855678Spl196000
48865678Spl196000 case SCMD_MODE_SENSE: /* mode_sense_6 */
48875678Spl196000 case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
48885678Spl196000 int capacity;
48895678Spl196000
48905678Spl196000 aac_free_dmamap(acp);
48915678Spl196000 if (dvp->size > 0xffffffffull)
48925678Spl196000 capacity = 0xfffffffful; /* 64-bit LBA */
48935678Spl196000 else
48945678Spl196000 capacity = dvp->size;
48955678Spl196000 aac_mode_sense(softs, pkt, cdbp, bp, capacity);
48965678Spl196000 aac_soft_callback(softs, acp);
48975678Spl196000 rval = TRAN_ACCEPT;
48985678Spl196000 break;
48995678Spl196000 }
49005678Spl196000
490110976SZhongyan.Gu@Sun.COM case SCMD_START_STOP:
490210976SZhongyan.Gu@Sun.COM if (softs->support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
490310976SZhongyan.Gu@Sun.COM acp->aac_cmd_fib = aac_cmd_fib_startstop;
490410976SZhongyan.Gu@Sun.COM acp->ac_comp = aac_startstop_complete;
490510976SZhongyan.Gu@Sun.COM rval = aac_do_io(softs, acp);
490610976SZhongyan.Gu@Sun.COM break;
490710976SZhongyan.Gu@Sun.COM }
490810976SZhongyan.Gu@Sun.COM /* FALLTHRU */
49095678Spl196000 case SCMD_TEST_UNIT_READY:
49105678Spl196000 case SCMD_REQUEST_SENSE:
49115678Spl196000 case SCMD_FORMAT:
49125678Spl196000 aac_free_dmamap(acp);
49135678Spl196000 if (bp && bp->b_un.b_addr && bp->b_bcount) {
49145678Spl196000 if (acp->flags & AAC_CMD_BUF_READ) {
49155678Spl196000 if (bp->b_flags & (B_PHYS|B_PAGEIO))
49165678Spl196000 bp_mapin(bp);
49175678Spl196000 bzero(bp->b_un.b_addr, bp->b_bcount);
49185678Spl196000 }
49195678Spl196000 pkt->pkt_state |= STATE_XFERRED_DATA;
49205678Spl196000 }
49215678Spl196000 aac_soft_callback(softs, acp);
49225678Spl196000 rval = TRAN_ACCEPT;
49235678Spl196000 break;
49245678Spl196000
49255678Spl196000 case SCMD_SYNCHRONIZE_CACHE:
49265678Spl196000 acp->flags |= AAC_CMD_NTAG;
49275678Spl196000 acp->aac_cmd_fib = aac_cmd_fib_sync;
49285678Spl196000 acp->ac_comp = aac_synccache_complete;
49295678Spl196000 rval = aac_do_io(softs, acp);
49305678Spl196000 break;
49315678Spl196000
49325678Spl196000 case SCMD_DOORLOCK:
49335678Spl196000 aac_free_dmamap(acp);
49345678Spl196000 dvp->locked = (pkt->pkt_cdbp[4] & 0x01) ? 1 : 0;
49355678Spl196000 aac_soft_callback(softs, acp);
49365678Spl196000 rval = TRAN_ACCEPT;
49375678Spl196000 break;
49385678Spl196000
49395678Spl196000 default: /* unknown command */
49405678Spl196000 aac_unknown_scmd(softs, acp);
49415678Spl196000 rval = TRAN_ACCEPT;
49425678Spl196000 break;
49435678Spl196000 }
49445678Spl196000
49455678Spl196000 return (rval);
49465678Spl196000 }
49475678Spl196000
49485678Spl196000 static int
aac_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)49495678Spl196000 aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
49505678Spl196000 {
49515678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
49525678Spl196000 struct aac_cmd *acp = PKT2AC(pkt);
49537567SXin.Chen@Sun.COM struct aac_device *dvp = acp->dvp;
49545678Spl196000 int rval;
49555678Spl196000
49565678Spl196000 DBCALLED(softs, 2);
49575678Spl196000
49585678Spl196000 /*
49595678Spl196000 * Reinitialize some fields of ac and pkt; the packet may
49605678Spl196000 * have been resubmitted
49615678Spl196000 */
49625678Spl196000 acp->flags &= AAC_CMD_CONSISTENT | AAC_CMD_DMA_PARTIAL | \
49635678Spl196000 AAC_CMD_BUF_READ | AAC_CMD_BUF_WRITE | AAC_CMD_DMA_VALID;
49645678Spl196000 acp->timeout = acp->pkt->pkt_time;
49655678Spl196000 if (pkt->pkt_flags & FLAG_NOINTR)
49665678Spl196000 acp->flags |= AAC_CMD_NO_INTR;
49677567SXin.Chen@Sun.COM #ifdef DEBUG
49687567SXin.Chen@Sun.COM acp->fib_flags = AACDB_FLAGS_FIB_SCMD;
49697567SXin.Chen@Sun.COM #endif
49705678Spl196000 pkt->pkt_reason = CMD_CMPLT;
49715678Spl196000 pkt->pkt_state = 0;
49725678Spl196000 pkt->pkt_statistics = 0;
49737567SXin.Chen@Sun.COM *pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
49745678Spl196000
49755678Spl196000 if (acp->flags & AAC_CMD_DMA_VALID) {
49765678Spl196000 pkt->pkt_resid = acp->bcount;
49775678Spl196000 /* Consistent packets need to be sync'ed first */
49785678Spl196000 if ((acp->flags & AAC_CMD_CONSISTENT) &&
49795678Spl196000 (acp->flags & AAC_CMD_BUF_WRITE))
49805678Spl196000 if (aac_dma_sync_ac(acp) != AACOK) {
49815678Spl196000 ddi_fm_service_impact(softs->devinfo_p,
49825678Spl196000 DDI_SERVICE_UNAFFECTED);
49835678Spl196000 return (TRAN_BADPKT);
49845678Spl196000 }
49855678Spl196000 } else {
49865678Spl196000 pkt->pkt_resid = 0;
49875678Spl196000 }
49885678Spl196000
49895678Spl196000 mutex_enter(&softs->io_lock);
49905678Spl196000 AACDB_PRINT_SCMD(softs, acp);
49917567SXin.Chen@Sun.COM if ((dvp->flags & (AAC_DFLAG_VALID | AAC_DFLAG_CONFIGURING)) &&
49927567SXin.Chen@Sun.COM !(softs->state & AAC_STATE_DEAD)) {
49937567SXin.Chen@Sun.COM if (dvp->type == AAC_DEV_LD) {
49947567SXin.Chen@Sun.COM if (ap->a_lun == 0)
49957567SXin.Chen@Sun.COM rval = aac_tran_start_ld(softs, acp);
49967567SXin.Chen@Sun.COM else
49977567SXin.Chen@Sun.COM goto error;
49987567SXin.Chen@Sun.COM } else {
49997567SXin.Chen@Sun.COM rval = aac_do_io(softs, acp);
50007567SXin.Chen@Sun.COM }
50015678Spl196000 } else {
50027567SXin.Chen@Sun.COM error:
50037567SXin.Chen@Sun.COM #ifdef DEBUG
50047567SXin.Chen@Sun.COM if (!(softs->state & AAC_STATE_DEAD)) {
50057567SXin.Chen@Sun.COM AACDB_PRINT_TRAN(softs,
50067567SXin.Chen@Sun.COM "Cannot send cmd to target t%dL%d: %s",
50077567SXin.Chen@Sun.COM ap->a_target, ap->a_lun,
50087567SXin.Chen@Sun.COM "target invalid");
50097567SXin.Chen@Sun.COM } else {
50107567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN,
50117567SXin.Chen@Sun.COM "Cannot send cmd to target t%dL%d: %s",
50127567SXin.Chen@Sun.COM ap->a_target, ap->a_lun,
50137567SXin.Chen@Sun.COM "adapter dead");
50147567SXin.Chen@Sun.COM }
50157567SXin.Chen@Sun.COM #endif
50165678Spl196000 rval = TRAN_FATAL_ERROR;
50175678Spl196000 }
50185678Spl196000 mutex_exit(&softs->io_lock);
50195678Spl196000 return (rval);
50205678Spl196000 }
50215678Spl196000
50225678Spl196000 static int
aac_tran_getcap(struct scsi_address * ap,char * cap,int whom)50235678Spl196000 aac_tran_getcap(struct scsi_address *ap, char *cap, int whom)
50245678Spl196000 {
50255678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
50267567SXin.Chen@Sun.COM struct aac_device *dvp;
50275678Spl196000 int rval;
50285678Spl196000
50295678Spl196000 DBCALLED(softs, 2);
50305678Spl196000
50315678Spl196000 /* We don't allow inquiring about capabilities for other targets */
50325678Spl196000 if (cap == NULL || whom == 0) {
50335678Spl196000 AACDB_PRINT(softs, CE_WARN,
50345678Spl196000 "GetCap> %s not supported: whom=%d", cap, whom);
50355678Spl196000 return (-1);
50365678Spl196000 }
50375678Spl196000
50385678Spl196000 mutex_enter(&softs->io_lock);
50397567SXin.Chen@Sun.COM dvp = AAC_DEV(softs, ap->a_target);
50407567SXin.Chen@Sun.COM if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
50415678Spl196000 mutex_exit(&softs->io_lock);
50427567SXin.Chen@Sun.COM AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to getcap",
50435678Spl196000 ap->a_target, ap->a_lun);
50445678Spl196000 return (-1);
50455678Spl196000 }
50465678Spl196000
50475678Spl196000 switch (scsi_hba_lookup_capstr(cap)) {
50485678Spl196000 case SCSI_CAP_ARQ: /* auto request sense */
50495678Spl196000 rval = 1;
50505678Spl196000 break;
50515678Spl196000 case SCSI_CAP_UNTAGGED_QING:
50525678Spl196000 case SCSI_CAP_TAGGED_QING:
50535678Spl196000 rval = 1;
50545678Spl196000 break;
50555678Spl196000 case SCSI_CAP_DMA_MAX:
50568551SPeng.L@Sun.COM rval = softs->dma_max;
50575678Spl196000 break;
50585678Spl196000 default:
50595678Spl196000 rval = -1;
50605678Spl196000 break;
50615678Spl196000 }
50625678Spl196000 mutex_exit(&softs->io_lock);
50635678Spl196000
50645678Spl196000 AACDB_PRINT_TRAN(softs, "GetCap> %s t%dL%d: rval=%d",
50655678Spl196000 cap, ap->a_target, ap->a_lun, rval);
50665678Spl196000 return (rval);
50675678Spl196000 }
50685678Spl196000
50695678Spl196000 /*ARGSUSED*/
50705678Spl196000 static int
aac_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)50715678Spl196000 aac_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
50725678Spl196000 {
50735678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
50747567SXin.Chen@Sun.COM struct aac_device *dvp;
50755678Spl196000 int rval;
50765678Spl196000
50775678Spl196000 DBCALLED(softs, 2);
50785678Spl196000
50795678Spl196000 /* We don't allow inquiring about capabilities for other targets */
50805678Spl196000 if (cap == NULL || whom == 0) {
50815678Spl196000 AACDB_PRINT(softs, CE_WARN,
50825678Spl196000 "SetCap> %s not supported: whom=%d", cap, whom);
50835678Spl196000 return (-1);
50845678Spl196000 }
50855678Spl196000
50865678Spl196000 mutex_enter(&softs->io_lock);
50877567SXin.Chen@Sun.COM dvp = AAC_DEV(softs, ap->a_target);
50887567SXin.Chen@Sun.COM if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
50895678Spl196000 mutex_exit(&softs->io_lock);
50907567SXin.Chen@Sun.COM AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to setcap",
50915678Spl196000 ap->a_target, ap->a_lun);
50925678Spl196000 return (-1);
50935678Spl196000 }
50945678Spl196000
50955678Spl196000 switch (scsi_hba_lookup_capstr(cap)) {
50965678Spl196000 case SCSI_CAP_ARQ:
50975678Spl196000 /* Force auto request sense */
50985678Spl196000 rval = (value == 1) ? 1 : 0;
50995678Spl196000 break;
51005678Spl196000 case SCSI_CAP_UNTAGGED_QING:
51015678Spl196000 case SCSI_CAP_TAGGED_QING:
51025678Spl196000 rval = (value == 1) ? 1 : 0;
51035678Spl196000 break;
51045678Spl196000 default:
51055678Spl196000 rval = -1;
51065678Spl196000 break;
51075678Spl196000 }
51085678Spl196000 mutex_exit(&softs->io_lock);
51095678Spl196000
51105678Spl196000 AACDB_PRINT_TRAN(softs, "SetCap> %s t%dL%d val=%d: rval=%d",
51115678Spl196000 cap, ap->a_target, ap->a_lun, value, rval);
51125678Spl196000 return (rval);
51135678Spl196000 }
51145678Spl196000
51155678Spl196000 static void
aac_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)51165678Spl196000 aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
51175678Spl196000 {
51185678Spl196000 struct aac_cmd *acp = PKT2AC(pkt);
51195678Spl196000
51205678Spl196000 DBCALLED(NULL, 2);
51215678Spl196000
51225678Spl196000 if (acp->sgt) {
51235678Spl196000 kmem_free(acp->sgt, sizeof (struct aac_sge) * \
51245678Spl196000 acp->left_cookien);
51255678Spl196000 }
51265678Spl196000 aac_free_dmamap(acp);
51275678Spl196000 ASSERT(acp->slotp == NULL);
51285678Spl196000 scsi_hba_pkt_free(ap, pkt);
51295678Spl196000 }
51305678Spl196000
51315678Spl196000 int
aac_cmd_dma_alloc(struct aac_softstate * softs,struct aac_cmd * acp,struct buf * bp,int flags,int (* cb)(),caddr_t arg)51325678Spl196000 aac_cmd_dma_alloc(struct aac_softstate *softs, struct aac_cmd *acp,
51335678Spl196000 struct buf *bp, int flags, int (*cb)(), caddr_t arg)
51345678Spl196000 {
51355678Spl196000 int kf = (cb == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
51365678Spl196000 uint_t oldcookiec;
51375678Spl196000 int bioerr;
51385678Spl196000 int rval;
51395678Spl196000
51405678Spl196000 oldcookiec = acp->left_cookien;
51415678Spl196000
51425678Spl196000 /* Move window to build s/g map */
51435678Spl196000 if (acp->total_nwin > 0) {
51445678Spl196000 if (++acp->cur_win < acp->total_nwin) {
51455678Spl196000 off_t off;
51465678Spl196000 size_t len;
51475678Spl196000
51485678Spl196000 rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
51495678Spl196000 &off, &len, &acp->cookie, &acp->left_cookien);
51505678Spl196000 if (rval == DDI_SUCCESS)
51515678Spl196000 goto get_dma_cookies;
51525678Spl196000 AACDB_PRINT(softs, CE_WARN,
51535678Spl196000 "ddi_dma_getwin() fail %d", rval);
51547567SXin.Chen@Sun.COM return (AACERR);
51555678Spl196000 }
51565678Spl196000 AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
51577567SXin.Chen@Sun.COM return (AACERR);
51585678Spl196000 }
51595678Spl196000
51605678Spl196000 /* We need to transfer data, so we alloc DMA resources for this pkt */
51615678Spl196000 if (bp && bp->b_bcount != 0 && !(acp->flags & AAC_CMD_DMA_VALID)) {
51625678Spl196000 uint_t dma_flags = 0;
51635678Spl196000 struct aac_sge *sge;
51645678Spl196000
51655678Spl196000 /*
51665678Spl196000 * We will still use this point to fake some
51675678Spl196000 * infomation in tran_start
51685678Spl196000 */
51695678Spl196000 acp->bp = bp;
51705678Spl196000
51715678Spl196000 /* Set dma flags */
51725678Spl196000 if (BUF_IS_READ(bp)) {
51735678Spl196000 dma_flags |= DDI_DMA_READ;
51745678Spl196000 acp->flags |= AAC_CMD_BUF_READ;
51755678Spl196000 } else {
51765678Spl196000 dma_flags |= DDI_DMA_WRITE;
51775678Spl196000 acp->flags |= AAC_CMD_BUF_WRITE;
51785678Spl196000 }
51795678Spl196000 if (flags & PKT_CONSISTENT)
51805678Spl196000 dma_flags |= DDI_DMA_CONSISTENT;
51815678Spl196000 if (flags & PKT_DMA_PARTIAL)
51825678Spl196000 dma_flags |= DDI_DMA_PARTIAL;
51835678Spl196000
51845678Spl196000 /* Alloc buf dma handle */
51855678Spl196000 if (!acp->buf_dma_handle) {
51865678Spl196000 rval = ddi_dma_alloc_handle(softs->devinfo_p,
51875678Spl196000 &softs->buf_dma_attr, cb, arg,
51885678Spl196000 &acp->buf_dma_handle);
51895678Spl196000 if (rval != DDI_SUCCESS) {
51905678Spl196000 AACDB_PRINT(softs, CE_WARN,
51915678Spl196000 "Can't allocate DMA handle, errno=%d",
51925678Spl196000 rval);
51935678Spl196000 goto error_out;
51945678Spl196000 }
51955678Spl196000 }
51965678Spl196000
51975678Spl196000 /* Bind buf */
51985678Spl196000 if (((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) {
51995678Spl196000 rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
52005678Spl196000 bp, dma_flags, cb, arg, &acp->cookie,
52015678Spl196000 &acp->left_cookien);
52025678Spl196000 } else {
52035678Spl196000 size_t bufsz;
52045678Spl196000
52055678Spl196000 AACDB_PRINT_TRAN(softs,
52065678Spl196000 "non-aligned buffer: addr=0x%p, cnt=%lu",
52075678Spl196000 (void *)bp->b_un.b_addr, bp->b_bcount);
52085678Spl196000 if (bp->b_flags & (B_PAGEIO|B_PHYS))
52095678Spl196000 bp_mapin(bp);
52105678Spl196000
52115678Spl196000 rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
52125678Spl196000 AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
52137567SXin.Chen@Sun.COM &softs->acc_attr, DDI_DMA_STREAMING,
52145678Spl196000 cb, arg, &acp->abp, &bufsz, &acp->abh);
52155678Spl196000
52165678Spl196000 if (rval != DDI_SUCCESS) {
52175678Spl196000 AACDB_PRINT(softs, CE_NOTE,
52185678Spl196000 "Cannot alloc DMA to non-aligned buf");
52195678Spl196000 bioerr = 0;
52205678Spl196000 goto error_out;
52215678Spl196000 }
52225678Spl196000
52235678Spl196000 if (acp->flags & AAC_CMD_BUF_WRITE)
52245678Spl196000 ddi_rep_put8(acp->abh,
52255678Spl196000 (uint8_t *)bp->b_un.b_addr,
52265678Spl196000 (uint8_t *)acp->abp, bp->b_bcount,
52275678Spl196000 DDI_DEV_AUTOINCR);
52285678Spl196000
52295678Spl196000 rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
52305678Spl196000 NULL, acp->abp, bufsz, dma_flags, cb, arg,
52315678Spl196000 &acp->cookie, &acp->left_cookien);
52325678Spl196000 }
52335678Spl196000
52345678Spl196000 switch (rval) {
52355678Spl196000 case DDI_DMA_PARTIAL_MAP:
52365678Spl196000 if (ddi_dma_numwin(acp->buf_dma_handle,
52375678Spl196000 &acp->total_nwin) == DDI_FAILURE) {
52385678Spl196000 AACDB_PRINT(softs, CE_WARN,
52395678Spl196000 "Cannot get number of DMA windows");
52405678Spl196000 bioerr = 0;
52415678Spl196000 goto error_out;
52425678Spl196000 }
52435678Spl196000 AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
52445678Spl196000 acp->left_cookien);
52455678Spl196000 acp->cur_win = 0;
52465678Spl196000 break;
52475678Spl196000
52485678Spl196000 case DDI_DMA_MAPPED:
52495678Spl196000 AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
52505678Spl196000 acp->left_cookien);
52515678Spl196000 acp->cur_win = 0;
52525678Spl196000 acp->total_nwin = 1;
52535678Spl196000 break;
52545678Spl196000
52555678Spl196000 case DDI_DMA_NORESOURCES:
52565678Spl196000 bioerr = 0;
52575678Spl196000 AACDB_PRINT(softs, CE_WARN,
52585678Spl196000 "Cannot bind buf for DMA: DDI_DMA_NORESOURCES");
52595678Spl196000 goto error_out;
52605678Spl196000 case DDI_DMA_BADATTR:
52615678Spl196000 case DDI_DMA_NOMAPPING:
52625678Spl196000 bioerr = EFAULT;
52635678Spl196000 AACDB_PRINT(softs, CE_WARN,
52645678Spl196000 "Cannot bind buf for DMA: DDI_DMA_NOMAPPING");
52655678Spl196000 goto error_out;
52665678Spl196000 case DDI_DMA_TOOBIG:
52675678Spl196000 bioerr = EINVAL;
52685678Spl196000 AACDB_PRINT(softs, CE_WARN,
52695678Spl196000 "Cannot bind buf for DMA: DDI_DMA_TOOBIG(%d)",
52705678Spl196000 bp->b_bcount);
52715678Spl196000 goto error_out;
52725678Spl196000 default:
52735678Spl196000 bioerr = EINVAL;
52745678Spl196000 AACDB_PRINT(softs, CE_WARN,
52755678Spl196000 "Cannot bind buf for DMA: %d", rval);
52765678Spl196000 goto error_out;
52775678Spl196000 }
52785678Spl196000 acp->flags |= AAC_CMD_DMA_VALID;
52795678Spl196000
52805678Spl196000 get_dma_cookies:
52815678Spl196000 ASSERT(acp->left_cookien > 0);
52825678Spl196000 if (acp->left_cookien > softs->aac_sg_tablesize) {
52835678Spl196000 AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
52845678Spl196000 acp->left_cookien);
52855678Spl196000 bioerr = EINVAL;
52865678Spl196000 goto error_out;
52875678Spl196000 }
52885678Spl196000 if (oldcookiec != acp->left_cookien && acp->sgt != NULL) {
52895678Spl196000 kmem_free(acp->sgt, sizeof (struct aac_sge) * \
52905678Spl196000 oldcookiec);
52915678Spl196000 acp->sgt = NULL;
52925678Spl196000 }
52935678Spl196000 if (acp->sgt == NULL) {
52945678Spl196000 acp->sgt = kmem_alloc(sizeof (struct aac_sge) * \
52955678Spl196000 acp->left_cookien, kf);
52965678Spl196000 if (acp->sgt == NULL) {
52975678Spl196000 AACDB_PRINT(softs, CE_WARN,
52985678Spl196000 "sgt kmem_alloc fail");
52995678Spl196000 bioerr = ENOMEM;
53005678Spl196000 goto error_out;
53015678Spl196000 }
53025678Spl196000 }
53035678Spl196000
53045678Spl196000 sge = &acp->sgt[0];
53055678Spl196000 sge->bcount = acp->cookie.dmac_size;
53065678Spl196000 sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
53075678Spl196000 sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
53085678Spl196000 acp->bcount = acp->cookie.dmac_size;
53095678Spl196000 for (sge++; sge < &acp->sgt[acp->left_cookien]; sge++) {
53105678Spl196000 ddi_dma_nextcookie(acp->buf_dma_handle, &acp->cookie);
53115678Spl196000 sge->bcount = acp->cookie.dmac_size;
53125678Spl196000 sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
53135678Spl196000 sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
53145678Spl196000 acp->bcount += acp->cookie.dmac_size;
53155678Spl196000 }
53165678Spl196000
53175678Spl196000 /*
53185678Spl196000 * Note: The old DMA engine do not correctly handle
53195678Spl196000 * dma_attr_maxxfer attribute. So we have to ensure
53205678Spl196000 * it by ourself.
53215678Spl196000 */
53225678Spl196000 if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
53235678Spl196000 AACDB_PRINT(softs, CE_NOTE,
53245678Spl196000 "large xfer size received %d\n", acp->bcount);
53255678Spl196000 bioerr = EINVAL;
53265678Spl196000 goto error_out;
53275678Spl196000 }
53285678Spl196000
53295678Spl196000 acp->total_xfer += acp->bcount;
53305678Spl196000
53315678Spl196000 if (acp->pkt) {
53325678Spl196000 /* Return remaining byte count */
53337567SXin.Chen@Sun.COM if (acp->total_xfer <= bp->b_bcount) {
53347567SXin.Chen@Sun.COM acp->pkt->pkt_resid = bp->b_bcount - \
53357567SXin.Chen@Sun.COM acp->total_xfer;
53367567SXin.Chen@Sun.COM } else {
53377567SXin.Chen@Sun.COM /*
53387567SXin.Chen@Sun.COM * Allocated DMA size is greater than the buf
53397567SXin.Chen@Sun.COM * size of bp. This is caused by devices like
53407567SXin.Chen@Sun.COM * tape. we have extra bytes allocated, but
53417567SXin.Chen@Sun.COM * the packet residual has to stay correct.
53427567SXin.Chen@Sun.COM */
53437567SXin.Chen@Sun.COM acp->pkt->pkt_resid = 0;
53447567SXin.Chen@Sun.COM }
53455678Spl196000 AACDB_PRINT_TRAN(softs,
53465678Spl196000 "bp=0x%p, xfered=%d/%d, resid=%d",
53475678Spl196000 (void *)bp->b_un.b_addr, (int)acp->total_xfer,
53485678Spl196000 (int)bp->b_bcount, (int)acp->pkt->pkt_resid);
53495678Spl196000 }
53505678Spl196000 }
53515678Spl196000 return (AACOK);
53525678Spl196000
53535678Spl196000 error_out:
53545678Spl196000 bioerror(bp, bioerr);
53555678Spl196000 return (AACERR);
53565678Spl196000 }
53575678Spl196000
53585678Spl196000 static struct scsi_pkt *
aac_tran_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)53595678Spl196000 aac_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
53605678Spl196000 struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
53615678Spl196000 int (*callback)(), caddr_t arg)
53625678Spl196000 {
53635678Spl196000 struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
53645678Spl196000 struct aac_cmd *acp, *new_acp;
53655678Spl196000
53665678Spl196000 DBCALLED(softs, 2);
53675678Spl196000
53685678Spl196000 /* Allocate pkt */
53695678Spl196000 if (pkt == NULL) {
53705678Spl196000 int slen;
53715678Spl196000
53725678Spl196000 /* Force auto request sense */
53735678Spl196000 slen = (statuslen > softs->slen) ? statuslen : softs->slen;
53745678Spl196000 pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
53755678Spl196000 slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
53765678Spl196000 if (pkt == NULL) {
53775678Spl196000 AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
53785678Spl196000 return (NULL);
53795678Spl196000 }
53805678Spl196000 acp = new_acp = PKT2AC(pkt);
53815678Spl196000 acp->pkt = pkt;
53825678Spl196000 acp->cmdlen = cmdlen;
53835678Spl196000
53847567SXin.Chen@Sun.COM if (ap->a_target < AAC_MAX_LD) {
53857567SXin.Chen@Sun.COM acp->dvp = &softs->containers[ap->a_target].dev;
53867567SXin.Chen@Sun.COM acp->aac_cmd_fib = softs->aac_cmd_fib;
53877567SXin.Chen@Sun.COM acp->ac_comp = aac_ld_complete;
53887567SXin.Chen@Sun.COM } else {
53897567SXin.Chen@Sun.COM _NOTE(ASSUMING_PROTECTED(softs->nondasds))
53907567SXin.Chen@Sun.COM
53917567SXin.Chen@Sun.COM acp->dvp = &softs->nondasds[AAC_PD(ap->a_target)].dev;
53927567SXin.Chen@Sun.COM acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
53937567SXin.Chen@Sun.COM acp->ac_comp = aac_pd_complete;
53947567SXin.Chen@Sun.COM }
53955678Spl196000 } else {
53965678Spl196000 acp = PKT2AC(pkt);
53975678Spl196000 new_acp = NULL;
53985678Spl196000 }
53995678Spl196000
54005678Spl196000 if (aac_cmd_dma_alloc(softs, acp, bp, flags, callback, arg) == AACOK)
54015678Spl196000 return (pkt);
54025678Spl196000
54035678Spl196000 if (new_acp)
54045678Spl196000 aac_tran_destroy_pkt(ap, pkt);
54055678Spl196000 return (NULL);
54065678Spl196000 }
54075678Spl196000
54085678Spl196000 /*
54095678Spl196000 * tran_sync_pkt(9E) - explicit DMA synchronization
54105678Spl196000 */
54115678Spl196000 /*ARGSUSED*/
54125678Spl196000 static void
aac_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)54135678Spl196000 aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
54145678Spl196000 {
54155678Spl196000 struct aac_cmd *acp = PKT2AC(pkt);
54165678Spl196000
54175678Spl196000 DBCALLED(NULL, 2);
54185678Spl196000
54195678Spl196000 if (aac_dma_sync_ac(acp) != AACOK)
54205678Spl196000 ddi_fm_service_impact(
54215678Spl196000 (AAC_TRAN2SOFTS(ap->a_hba_tran))->devinfo_p,
54225678Spl196000 DDI_SERVICE_UNAFFECTED);
54235678Spl196000 }
54245678Spl196000
54255678Spl196000 /*
54265678Spl196000 * tran_dmafree(9E) - deallocate DMA resources allocated for command
54275678Spl196000 */
54285678Spl196000 /*ARGSUSED*/
54295678Spl196000 static void
aac_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)54305678Spl196000 aac_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
54315678Spl196000 {
54325678Spl196000 struct aac_cmd *acp = PKT2AC(pkt);
54335678Spl196000
54345678Spl196000 DBCALLED(NULL, 2);
54355678Spl196000
54365678Spl196000 aac_free_dmamap(acp);
54375678Spl196000 }
54385678Spl196000
54395678Spl196000 static int
aac_do_quiesce(struct aac_softstate * softs)54405678Spl196000 aac_do_quiesce(struct aac_softstate *softs)
54415678Spl196000 {
54425678Spl196000 aac_hold_bus(softs, AAC_IOCMD_ASYNC);
54435678Spl196000 if (softs->bus_ncmds[AAC_CMDQ_ASYNC]) {
54445678Spl196000 aac_start_drain(softs);
54455678Spl196000 do {
54465678Spl196000 if (cv_wait_sig(&softs->drain_cv,
54475678Spl196000 &softs->io_lock) == 0) {
54485678Spl196000 /* Quiesce has been interrupted */
54495678Spl196000 aac_stop_drain(softs);
54505678Spl196000 aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
54515678Spl196000 aac_start_waiting_io(softs);
54525678Spl196000 return (AACERR);
54535678Spl196000 }
54545678Spl196000 } while (softs->bus_ncmds[AAC_CMDQ_ASYNC]);
54555678Spl196000 aac_stop_drain(softs);
54565678Spl196000 }
54575678Spl196000
54585678Spl196000 softs->state |= AAC_STATE_QUIESCED;
54595678Spl196000 return (AACOK);
54605678Spl196000 }
54615678Spl196000
54625678Spl196000 static int
aac_tran_quiesce(dev_info_t * dip)54635678Spl196000 aac_tran_quiesce(dev_info_t *dip)
54645678Spl196000 {
54655678Spl196000 struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
54665678Spl196000 int rval;
54675678Spl196000
54685678Spl196000 DBCALLED(softs, 1);
54695678Spl196000
54705678Spl196000 mutex_enter(&softs->io_lock);
54715678Spl196000 if (aac_do_quiesce(softs) == AACOK)
54725678Spl196000 rval = 0;
54735678Spl196000 else
54745678Spl196000 rval = 1;
54755678Spl196000 mutex_exit(&softs->io_lock);
54765678Spl196000 return (rval);
54775678Spl196000 }
54785678Spl196000
54795678Spl196000 static int
aac_do_unquiesce(struct aac_softstate * softs)54805678Spl196000 aac_do_unquiesce(struct aac_softstate *softs)
54815678Spl196000 {
54825678Spl196000 softs->state &= ~AAC_STATE_QUIESCED;
54835678Spl196000 aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
54845678Spl196000
54855678Spl196000 aac_start_waiting_io(softs);
54865678Spl196000 return (AACOK);
54875678Spl196000 }
54885678Spl196000
54895678Spl196000 static int
aac_tran_unquiesce(dev_info_t * dip)54905678Spl196000 aac_tran_unquiesce(dev_info_t *dip)
54915678Spl196000 {
54925678Spl196000 struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
54935678Spl196000 int rval;
54945678Spl196000
54955678Spl196000 DBCALLED(softs, 1);
54965678Spl196000
54975678Spl196000 mutex_enter(&softs->io_lock);
54985678Spl196000 if (aac_do_unquiesce(softs) == AACOK)
54995678Spl196000 rval = 0;
55005678Spl196000 else
55015678Spl196000 rval = 1;
55025678Spl196000 mutex_exit(&softs->io_lock);
55035678Spl196000 return (rval);
55045678Spl196000 }
55055678Spl196000
55065678Spl196000 static int
aac_hba_setup(struct aac_softstate * softs)55075678Spl196000 aac_hba_setup(struct aac_softstate *softs)
55085678Spl196000 {
55095678Spl196000 scsi_hba_tran_t *hba_tran;
55105678Spl196000 int rval;
55115678Spl196000
55125678Spl196000 hba_tran = scsi_hba_tran_alloc(softs->devinfo_p, SCSI_HBA_CANSLEEP);
55135678Spl196000 if (hba_tran == NULL)
55145678Spl196000 return (AACERR);
55155678Spl196000 hba_tran->tran_hba_private = softs;
55165678Spl196000 hba_tran->tran_tgt_init = aac_tran_tgt_init;
55177567SXin.Chen@Sun.COM hba_tran->tran_tgt_free = aac_tran_tgt_free;
55185678Spl196000 hba_tran->tran_tgt_probe = scsi_hba_probe;
55195678Spl196000 hba_tran->tran_start = aac_tran_start;
55205678Spl196000 hba_tran->tran_getcap = aac_tran_getcap;
55215678Spl196000 hba_tran->tran_setcap = aac_tran_setcap;
55225678Spl196000 hba_tran->tran_init_pkt = aac_tran_init_pkt;
55235678Spl196000 hba_tran->tran_destroy_pkt = aac_tran_destroy_pkt;
55245678Spl196000 hba_tran->tran_reset = aac_tran_reset;
55255678Spl196000 hba_tran->tran_abort = aac_tran_abort;
55265678Spl196000 hba_tran->tran_sync_pkt = aac_tran_sync_pkt;
55275678Spl196000 hba_tran->tran_dmafree = aac_tran_dmafree;
55285678Spl196000 hba_tran->tran_quiesce = aac_tran_quiesce;
55295678Spl196000 hba_tran->tran_unquiesce = aac_tran_unquiesce;
55307567SXin.Chen@Sun.COM hba_tran->tran_bus_config = aac_tran_bus_config;
55315678Spl196000 rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
55325678Spl196000 hba_tran, 0);
55335678Spl196000 if (rval != DDI_SUCCESS) {
55345678Spl196000 scsi_hba_tran_free(hba_tran);
55355678Spl196000 AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
55365678Spl196000 return (AACERR);
55375678Spl196000 }
55385678Spl196000
55397567SXin.Chen@Sun.COM softs->hba_tran = hba_tran;
55405678Spl196000 return (AACOK);
55415678Spl196000 }
55425678Spl196000
55435678Spl196000 /*
55445678Spl196000 * FIB setup operations
55455678Spl196000 */
55465678Spl196000
55475678Spl196000 /*
55485678Spl196000 * Init FIB header
55495678Spl196000 */
55505678Spl196000 static void
aac_cmd_fib_header(struct aac_softstate * softs,struct aac_cmd * acp,uint16_t cmd)555111348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp,
555211348SZhongyan.Gu@Sun.COM uint16_t cmd)
555311348SZhongyan.Gu@Sun.COM {
555411348SZhongyan.Gu@Sun.COM struct aac_slot *slotp = acp->slotp;
55555678Spl196000 ddi_acc_handle_t acc = slotp->fib_acc_handle;
55565678Spl196000 struct aac_fib *fibp = slotp->fibp;
55575678Spl196000 uint32_t xfer_state;
55585678Spl196000
55595678Spl196000 xfer_state =
55605678Spl196000 AAC_FIBSTATE_HOSTOWNED |
55615678Spl196000 AAC_FIBSTATE_INITIALISED |
55625678Spl196000 AAC_FIBSTATE_EMPTY |
556311964SXin.Chen@Sun.COM AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
55645678Spl196000 AAC_FIBSTATE_FROMHOST |
55655678Spl196000 AAC_FIBSTATE_REXPECTED |
55665678Spl196000 AAC_FIBSTATE_NORM;
556711348SZhongyan.Gu@Sun.COM
556811964SXin.Chen@Sun.COM if (!(acp->flags & AAC_CMD_SYNC))
556911964SXin.Chen@Sun.COM xfer_state |= AAC_FIBSTATE_ASYNC;
55705678Spl196000
55715678Spl196000 ddi_put32(acc, &fibp->Header.XferState, xfer_state);
55725678Spl196000 ddi_put16(acc, &fibp->Header.Command, cmd);
55735678Spl196000 ddi_put8(acc, &fibp->Header.StructType, AAC_FIBTYPE_TFIB);
55745678Spl196000 ddi_put8(acc, &fibp->Header.Flags, 0); /* don't care */
557511348SZhongyan.Gu@Sun.COM ddi_put16(acc, &fibp->Header.Size, acp->fib_size);
557611348SZhongyan.Gu@Sun.COM ddi_put16(acc, &fibp->Header.SenderSize, softs->aac_max_fib_size);
55775678Spl196000 ddi_put32(acc, &fibp->Header.SenderFibAddress, (slotp->index << 2));
55785678Spl196000 ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
55795678Spl196000 ddi_put32(acc, &fibp->Header.SenderData, 0); /* don't care */
55805678Spl196000 }
55815678Spl196000
55825678Spl196000 /*
55835678Spl196000 * Init FIB for raw IO command
55845678Spl196000 */
55855678Spl196000 static void
aac_cmd_fib_rawio(struct aac_softstate * softs,struct aac_cmd * acp)55865678Spl196000 aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp)
55875678Spl196000 {
55885678Spl196000 ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
55895678Spl196000 struct aac_raw_io *io = (struct aac_raw_io *)&acp->slotp->fibp->data[0];
55905678Spl196000 struct aac_sg_entryraw *sgp;
55915678Spl196000 struct aac_sge *sge;
55925678Spl196000
55935678Spl196000 /* Calculate FIB size */
55945678Spl196000 acp->fib_size = sizeof (struct aac_fib_header) + \
55955678Spl196000 sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
55965678Spl196000 sizeof (struct aac_sg_entryraw);
55975678Spl196000
559811348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, RawIo);
55995678Spl196000
56005678Spl196000 ddi_put16(acc, &io->Flags, (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0);
56015678Spl196000 ddi_put16(acc, &io->BpTotal, 0);
56025678Spl196000 ddi_put16(acc, &io->BpComplete, 0);
56035678Spl196000
56045678Spl196000 ddi_put32(acc, AAC_LO32(&io->BlockNumber), AAC_LS32(acp->blkno));
56055678Spl196000 ddi_put32(acc, AAC_HI32(&io->BlockNumber), AAC_MS32(acp->blkno));
56065678Spl196000 ddi_put16(acc, &io->ContainerId,
56075678Spl196000 ((struct aac_container *)acp->dvp)->cid);
56085678Spl196000
56095678Spl196000 /* Fill SG table */
56105678Spl196000 ddi_put32(acc, &io->SgMapRaw.SgCount, acp->left_cookien);
56115678Spl196000 ddi_put32(acc, &io->ByteCount, acp->bcount);
56125678Spl196000
56135678Spl196000 for (sge = &acp->sgt[0], sgp = &io->SgMapRaw.SgEntryRaw[0];
56145678Spl196000 sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
56155678Spl196000 ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
56165678Spl196000 ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
56175678Spl196000 ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
56185678Spl196000 sgp->Next = 0;
56195678Spl196000 sgp->Prev = 0;
56205678Spl196000 sgp->Flags = 0;
56215678Spl196000 }
56225678Spl196000 }
56235678Spl196000
56245678Spl196000 /* Init FIB for 64-bit block IO command */
56255678Spl196000 static void
aac_cmd_fib_brw64(struct aac_softstate * softs,struct aac_cmd * acp)56265678Spl196000 aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp)
56275678Spl196000 {
56285678Spl196000 ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
56295678Spl196000 struct aac_blockread64 *br = (struct aac_blockread64 *) \
56305678Spl196000 &acp->slotp->fibp->data[0];
56315678Spl196000 struct aac_sg_entry64 *sgp;
56325678Spl196000 struct aac_sge *sge;
56335678Spl196000
56345678Spl196000 acp->fib_size = sizeof (struct aac_fib_header) + \
56355678Spl196000 sizeof (struct aac_blockread64) + (acp->left_cookien - 1) * \
56365678Spl196000 sizeof (struct aac_sg_entry64);
56375678Spl196000
563811348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, ContainerCommand64);
56395678Spl196000
56405678Spl196000 /*
56415678Spl196000 * The definitions for aac_blockread64 and aac_blockwrite64
56425678Spl196000 * are the same.
56435678Spl196000 */
56445678Spl196000 ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
56455678Spl196000 ddi_put16(acc, &br->ContainerId,
56465678Spl196000 ((struct aac_container *)acp->dvp)->cid);
56475678Spl196000 ddi_put32(acc, &br->Command, (acp->flags & AAC_CMD_BUF_READ) ?
56485678Spl196000 VM_CtHostRead64 : VM_CtHostWrite64);
56495678Spl196000 ddi_put16(acc, &br->Pad, 0);
56505678Spl196000 ddi_put16(acc, &br->Flags, 0);
56515678Spl196000
56525678Spl196000 /* Fill SG table */
56535678Spl196000 ddi_put32(acc, &br->SgMap64.SgCount, acp->left_cookien);
56545678Spl196000 ddi_put16(acc, &br->SectorCount, acp->bcount / AAC_BLK_SIZE);
56555678Spl196000
56565678Spl196000 for (sge = &acp->sgt[0], sgp = &br->SgMap64.SgEntry64[0];
56575678Spl196000 sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
56585678Spl196000 ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
56595678Spl196000 ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
56605678Spl196000 ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
56615678Spl196000 }
56625678Spl196000 }
56635678Spl196000
56645678Spl196000 /* Init FIB for block IO command */
56655678Spl196000 static void
aac_cmd_fib_brw(struct aac_softstate * softs,struct aac_cmd * acp)56665678Spl196000 aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp)
56675678Spl196000 {
56685678Spl196000 ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
56695678Spl196000 struct aac_blockread *br = (struct aac_blockread *) \
56705678Spl196000 &acp->slotp->fibp->data[0];
56715678Spl196000 struct aac_sg_entry *sgp;
56725678Spl196000 struct aac_sge *sge = &acp->sgt[0];
56735678Spl196000
56745678Spl196000 if (acp->flags & AAC_CMD_BUF_READ) {
56755678Spl196000 acp->fib_size = sizeof (struct aac_fib_header) + \
56765678Spl196000 sizeof (struct aac_blockread) + (acp->left_cookien - 1) * \
56775678Spl196000 sizeof (struct aac_sg_entry);
56785678Spl196000
56795678Spl196000 ddi_put32(acc, &br->Command, VM_CtBlockRead);
56805678Spl196000 ddi_put32(acc, &br->SgMap.SgCount, acp->left_cookien);
56815678Spl196000 sgp = &br->SgMap.SgEntry[0];
56825678Spl196000 } else {
56835678Spl196000 struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
56845678Spl196000
56855678Spl196000 acp->fib_size = sizeof (struct aac_fib_header) + \
56865678Spl196000 sizeof (struct aac_blockwrite) + (acp->left_cookien - 1) * \
56875678Spl196000 sizeof (struct aac_sg_entry);
56885678Spl196000
56895678Spl196000 ddi_put32(acc, &bw->Command, VM_CtBlockWrite);
56905678Spl196000 ddi_put32(acc, &bw->Stable, CUNSTABLE);
56915678Spl196000 ddi_put32(acc, &bw->SgMap.SgCount, acp->left_cookien);
56925678Spl196000 sgp = &bw->SgMap.SgEntry[0];
56935678Spl196000 }
569411348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, ContainerCommand);
56955678Spl196000
56965678Spl196000 /*
56975678Spl196000 * aac_blockread and aac_blockwrite have the similar
56985678Spl196000 * structure head, so use br for bw here
56995678Spl196000 */
57005678Spl196000 ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
57015678Spl196000 ddi_put32(acc, &br->ContainerId,
57025678Spl196000 ((struct aac_container *)acp->dvp)->cid);
57035678Spl196000 ddi_put32(acc, &br->ByteCount, acp->bcount);
57045678Spl196000
57055678Spl196000 /* Fill SG table */
57065678Spl196000 for (sge = &acp->sgt[0];
57075678Spl196000 sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
57085678Spl196000 ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
57095678Spl196000 ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
57105678Spl196000 }
57115678Spl196000 }
57125678Spl196000
57135678Spl196000 /*ARGSUSED*/
57145678Spl196000 void
aac_cmd_fib_copy(struct aac_softstate * softs,struct aac_cmd * acp)57155678Spl196000 aac_cmd_fib_copy(struct aac_softstate *softs, struct aac_cmd *acp)
57165678Spl196000 {
57175678Spl196000 struct aac_slot *slotp = acp->slotp;
57185678Spl196000 struct aac_fib *fibp = slotp->fibp;
57195678Spl196000 ddi_acc_handle_t acc = slotp->fib_acc_handle;
57205678Spl196000
57215678Spl196000 ddi_rep_put8(acc, (uint8_t *)acp->fibp, (uint8_t *)fibp,
57225678Spl196000 acp->fib_size, /* only copy data of needed length */
57235678Spl196000 DDI_DEV_AUTOINCR);
57245678Spl196000 ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
57255678Spl196000 ddi_put32(acc, &fibp->Header.SenderFibAddress, slotp->index << 2);
57265678Spl196000 }
57275678Spl196000
57285678Spl196000 static void
aac_cmd_fib_sync(struct aac_softstate * softs,struct aac_cmd * acp)57295678Spl196000 aac_cmd_fib_sync(struct aac_softstate *softs, struct aac_cmd *acp)
57305678Spl196000 {
573111348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
57325678Spl196000 struct aac_synchronize_command *sync =
573311348SZhongyan.Gu@Sun.COM (struct aac_synchronize_command *)&acp->slotp->fibp->data[0];
573411348SZhongyan.Gu@Sun.COM
573511348SZhongyan.Gu@Sun.COM acp->fib_size = AAC_FIB_SIZEOF(struct aac_synchronize_command);
573611348SZhongyan.Gu@Sun.COM
573711348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, ContainerCommand);
57385678Spl196000 ddi_put32(acc, &sync->Command, VM_ContainerConfig);
57395678Spl196000 ddi_put32(acc, &sync->Type, (uint32_t)CT_FLUSH_CACHE);
57405678Spl196000 ddi_put32(acc, &sync->Cid, ((struct aac_container *)acp->dvp)->cid);
57415678Spl196000 ddi_put32(acc, &sync->Count,
57425678Spl196000 sizeof (((struct aac_synchronize_reply *)0)->Data));
57435678Spl196000 }
57445678Spl196000
57455678Spl196000 /*
574610976SZhongyan.Gu@Sun.COM * Start/Stop unit (Power Management)
574710976SZhongyan.Gu@Sun.COM */
574810976SZhongyan.Gu@Sun.COM static void
aac_cmd_fib_startstop(struct aac_softstate * softs,struct aac_cmd * acp)574910976SZhongyan.Gu@Sun.COM aac_cmd_fib_startstop(struct aac_softstate *softs, struct aac_cmd *acp)
575010976SZhongyan.Gu@Sun.COM {
575111348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
575210976SZhongyan.Gu@Sun.COM struct aac_Container *cmd =
575311348SZhongyan.Gu@Sun.COM (struct aac_Container *)&acp->slotp->fibp->data[0];
575410976SZhongyan.Gu@Sun.COM union scsi_cdb *cdbp = (void *)acp->pkt->pkt_cdbp;
575510976SZhongyan.Gu@Sun.COM
575610976SZhongyan.Gu@Sun.COM acp->fib_size = AAC_FIB_SIZEOF(struct aac_Container);
575710976SZhongyan.Gu@Sun.COM
575811348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, ContainerCommand);
575910976SZhongyan.Gu@Sun.COM bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
576010976SZhongyan.Gu@Sun.COM ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
576110976SZhongyan.Gu@Sun.COM ddi_put32(acc, &cmd->CTCommand.command, CT_PM_DRIVER_SUPPORT);
576210976SZhongyan.Gu@Sun.COM ddi_put32(acc, &cmd->CTCommand.param[0], cdbp->cdb_opaque[4] & 1 ? \
576310976SZhongyan.Gu@Sun.COM AAC_PM_DRIVERSUP_START_UNIT : AAC_PM_DRIVERSUP_STOP_UNIT);
576410976SZhongyan.Gu@Sun.COM ddi_put32(acc, &cmd->CTCommand.param[1],
576510976SZhongyan.Gu@Sun.COM ((struct aac_container *)acp->dvp)->cid);
576610976SZhongyan.Gu@Sun.COM ddi_put32(acc, &cmd->CTCommand.param[2], cdbp->cdb_opaque[1] & 1);
576710976SZhongyan.Gu@Sun.COM }
576810976SZhongyan.Gu@Sun.COM
576910976SZhongyan.Gu@Sun.COM /*
57705678Spl196000 * Init FIB for pass-through SCMD
57715678Spl196000 */
57725678Spl196000 static void
aac_cmd_fib_srb(struct aac_cmd * acp)57735678Spl196000 aac_cmd_fib_srb(struct aac_cmd *acp)
57745678Spl196000 {
577511348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
577611348SZhongyan.Gu@Sun.COM struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
57777567SXin.Chen@Sun.COM uint8_t *cdb;
57785678Spl196000
57795678Spl196000 ddi_put32(acc, &srb->function, SRBF_ExecuteScsi);
57805678Spl196000 ddi_put32(acc, &srb->retry_limit, 0);
57815678Spl196000 ddi_put32(acc, &srb->cdb_size, acp->cmdlen);
57825678Spl196000 ddi_put32(acc, &srb->timeout, 0); /* use driver timeout */
57837567SXin.Chen@Sun.COM if (acp->fibp == NULL) {
57847567SXin.Chen@Sun.COM if (acp->flags & AAC_CMD_BUF_READ)
57857567SXin.Chen@Sun.COM ddi_put32(acc, &srb->flags, SRB_DataIn);
57867567SXin.Chen@Sun.COM else if (acp->flags & AAC_CMD_BUF_WRITE)
57877567SXin.Chen@Sun.COM ddi_put32(acc, &srb->flags, SRB_DataOut);
57887567SXin.Chen@Sun.COM ddi_put32(acc, &srb->channel,
57897567SXin.Chen@Sun.COM ((struct aac_nondasd *)acp->dvp)->bus);
57907567SXin.Chen@Sun.COM ddi_put32(acc, &srb->id, ((struct aac_nondasd *)acp->dvp)->tid);
57917567SXin.Chen@Sun.COM ddi_put32(acc, &srb->lun, 0);
57927567SXin.Chen@Sun.COM cdb = acp->pkt->pkt_cdbp;
57937567SXin.Chen@Sun.COM } else {
57947567SXin.Chen@Sun.COM struct aac_srb *srb0 = (struct aac_srb *)&acp->fibp->data[0];
57957567SXin.Chen@Sun.COM
57967567SXin.Chen@Sun.COM ddi_put32(acc, &srb->flags, srb0->flags);
57977567SXin.Chen@Sun.COM ddi_put32(acc, &srb->channel, srb0->channel);
57987567SXin.Chen@Sun.COM ddi_put32(acc, &srb->id, srb0->id);
57997567SXin.Chen@Sun.COM ddi_put32(acc, &srb->lun, srb0->lun);
58007567SXin.Chen@Sun.COM cdb = srb0->cdb;
58017567SXin.Chen@Sun.COM }
58027567SXin.Chen@Sun.COM ddi_rep_put8(acc, cdb, srb->cdb, acp->cmdlen, DDI_DEV_AUTOINCR);
58035678Spl196000 }
58045678Spl196000
58055678Spl196000 static void
aac_cmd_fib_scsi32(struct aac_softstate * softs,struct aac_cmd * acp)58065678Spl196000 aac_cmd_fib_scsi32(struct aac_softstate *softs, struct aac_cmd *acp)
58075678Spl196000 {
58085678Spl196000 ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
58095678Spl196000 struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
58105678Spl196000 struct aac_sg_entry *sgp;
58115678Spl196000 struct aac_sge *sge;
58125678Spl196000
58135678Spl196000 acp->fib_size = sizeof (struct aac_fib_header) + \
58145678Spl196000 sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
58155678Spl196000 acp->left_cookien * sizeof (struct aac_sg_entry);
58165678Spl196000
58175678Spl196000 /* Fill FIB and SRB headers, and copy cdb */
581811348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, ScsiPortCommand);
58195678Spl196000 aac_cmd_fib_srb(acp);
58205678Spl196000
58215678Spl196000 /* Fill SG table */
58225678Spl196000 ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
58235678Spl196000 ddi_put32(acc, &srb->count, acp->bcount);
58245678Spl196000
58255678Spl196000 for (sge = &acp->sgt[0], sgp = &srb->sg.SgEntry[0];
58265678Spl196000 sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
58275678Spl196000 ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
58285678Spl196000 ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
58295678Spl196000 }
58305678Spl196000 }
58315678Spl196000
58325678Spl196000 static void
aac_cmd_fib_scsi64(struct aac_softstate * softs,struct aac_cmd * acp)58335678Spl196000 aac_cmd_fib_scsi64(struct aac_softstate *softs, struct aac_cmd *acp)
58345678Spl196000 {
58355678Spl196000 ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
58365678Spl196000 struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
58375678Spl196000 struct aac_sg_entry64 *sgp;
58385678Spl196000 struct aac_sge *sge;
58395678Spl196000
58405678Spl196000 acp->fib_size = sizeof (struct aac_fib_header) + \
58415678Spl196000 sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
58425678Spl196000 acp->left_cookien * sizeof (struct aac_sg_entry64);
58435678Spl196000
58445678Spl196000 /* Fill FIB and SRB headers, and copy cdb */
584511348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(softs, acp, ScsiPortCommandU64);
58465678Spl196000 aac_cmd_fib_srb(acp);
58475678Spl196000
58485678Spl196000 /* Fill SG table */
58495678Spl196000 ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
58505678Spl196000 ddi_put32(acc, &srb->count, acp->bcount);
58515678Spl196000
58525678Spl196000 for (sge = &acp->sgt[0],
58535678Spl196000 sgp = &((struct aac_sg_table64 *)&srb->sg)->SgEntry64[0];
58545678Spl196000 sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
58555678Spl196000 ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
58565678Spl196000 ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
58575678Spl196000 ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
58585678Spl196000 }
58595678Spl196000 }
58605678Spl196000
58615678Spl196000 static int
aac_cmd_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)58625678Spl196000 aac_cmd_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
58635678Spl196000 {
58645678Spl196000 struct aac_slot *slotp;
58655678Spl196000
58665678Spl196000 if (slotp = aac_get_slot(softs)) {
58675678Spl196000 acp->slotp = slotp;
58685678Spl196000 slotp->acp = acp;
58695678Spl196000 acp->aac_cmd_fib(softs, acp);
58705678Spl196000 (void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0,
58715678Spl196000 DDI_DMA_SYNC_FORDEV);
58725678Spl196000 return (AACOK);
58735678Spl196000 }
58745678Spl196000 return (AACERR);
58755678Spl196000 }
58765678Spl196000
58775678Spl196000 static int
aac_bind_io(struct aac_softstate * softs,struct aac_cmd * acp)58785678Spl196000 aac_bind_io(struct aac_softstate *softs, struct aac_cmd *acp)
58795678Spl196000 {
58807567SXin.Chen@Sun.COM struct aac_device *dvp = acp->dvp;
58815678Spl196000 int q = AAC_CMDQ(acp);
58825678Spl196000
588311636SXin.Chen@Sun.COM if (softs->bus_ncmds[q] < softs->bus_throttle[q]) {
588411636SXin.Chen@Sun.COM if (dvp) {
588511636SXin.Chen@Sun.COM if (dvp->ncmds[q] < dvp->throttle[q]) {
588611636SXin.Chen@Sun.COM if (!(acp->flags & AAC_CMD_NTAG) ||
588711636SXin.Chen@Sun.COM dvp->ncmds[q] == 0) {
588811636SXin.Chen@Sun.COM return (aac_cmd_slot_bind(softs, acp));
588911636SXin.Chen@Sun.COM }
589011636SXin.Chen@Sun.COM ASSERT(q == AAC_CMDQ_ASYNC);
589111636SXin.Chen@Sun.COM aac_set_throttle(softs, dvp, AAC_CMDQ_ASYNC,
589211636SXin.Chen@Sun.COM AAC_THROTTLE_DRAIN);
58935678Spl196000 }
589411636SXin.Chen@Sun.COM } else {
589511636SXin.Chen@Sun.COM return (aac_cmd_slot_bind(softs, acp));
58965678Spl196000 }
58975678Spl196000 }
58985678Spl196000 return (AACERR);
58995678Spl196000 }
59005678Spl196000
590111348SZhongyan.Gu@Sun.COM static int
aac_sync_fib_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)590211348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
590311348SZhongyan.Gu@Sun.COM {
590411348SZhongyan.Gu@Sun.COM struct aac_slot *slotp;
590511348SZhongyan.Gu@Sun.COM
590611636SXin.Chen@Sun.COM while (softs->sync_ac.slotp)
590711636SXin.Chen@Sun.COM cv_wait(&softs->sync_fib_cv, &softs->io_lock);
590811636SXin.Chen@Sun.COM
590911348SZhongyan.Gu@Sun.COM if (slotp = aac_get_slot(softs)) {
591011348SZhongyan.Gu@Sun.COM ASSERT(acp->slotp == NULL);
591111348SZhongyan.Gu@Sun.COM
591211348SZhongyan.Gu@Sun.COM acp->slotp = slotp;
591311348SZhongyan.Gu@Sun.COM slotp->acp = acp;
591411348SZhongyan.Gu@Sun.COM return (AACOK);
591511348SZhongyan.Gu@Sun.COM }
591611348SZhongyan.Gu@Sun.COM return (AACERR);
591711348SZhongyan.Gu@Sun.COM }
591811348SZhongyan.Gu@Sun.COM
591911348SZhongyan.Gu@Sun.COM static void
aac_sync_fib_slot_release(struct aac_softstate * softs,struct aac_cmd * acp)592011348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(struct aac_softstate *softs, struct aac_cmd *acp)
592111348SZhongyan.Gu@Sun.COM {
592211348SZhongyan.Gu@Sun.COM ASSERT(acp->slotp);
592311348SZhongyan.Gu@Sun.COM
592411348SZhongyan.Gu@Sun.COM aac_release_slot(softs, acp->slotp);
592511348SZhongyan.Gu@Sun.COM acp->slotp->acp = NULL;
592611348SZhongyan.Gu@Sun.COM acp->slotp = NULL;
592711636SXin.Chen@Sun.COM
592811636SXin.Chen@Sun.COM cv_signal(&softs->sync_fib_cv);
592911348SZhongyan.Gu@Sun.COM }
593011348SZhongyan.Gu@Sun.COM
59315678Spl196000 static void
aac_start_io(struct aac_softstate * softs,struct aac_cmd * acp)59325678Spl196000 aac_start_io(struct aac_softstate *softs, struct aac_cmd *acp)
59335678Spl196000 {
59345678Spl196000 struct aac_slot *slotp = acp->slotp;
59355678Spl196000 int q = AAC_CMDQ(acp);
59365678Spl196000 int rval;
59375678Spl196000
59385678Spl196000 /* Set ac and pkt */
59395678Spl196000 if (acp->pkt) { /* ac from ioctl has no pkt */
59405678Spl196000 acp->pkt->pkt_state |=
59415678Spl196000 STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
59425678Spl196000 }
59435678Spl196000 if (acp->timeout) /* 0 indicates no timeout */
59445678Spl196000 acp->timeout += aac_timebase + aac_tick;
59455678Spl196000
59465678Spl196000 if (acp->dvp)
59475678Spl196000 acp->dvp->ncmds[q]++;
59485678Spl196000 softs->bus_ncmds[q]++;
59495678Spl196000 aac_cmd_enqueue(&softs->q_busy, acp);
59505678Spl196000
59517567SXin.Chen@Sun.COM AACDB_PRINT_FIB(softs, slotp);
59527567SXin.Chen@Sun.COM
59535678Spl196000 if (softs->flags & AAC_FLAGS_NEW_COMM) {
59545678Spl196000 rval = aac_send_command(softs, slotp);
59555678Spl196000 } else {
59565678Spl196000 /*
59575678Spl196000 * If fib can not be enqueued, the adapter is in an abnormal
59585678Spl196000 * state, there will be no interrupt to us.
59595678Spl196000 */
59605678Spl196000 rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
59615678Spl196000 slotp->fib_phyaddr, acp->fib_size);
59625678Spl196000 }
59635678Spl196000
59645678Spl196000 if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS)
59655678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
59665678Spl196000
59675678Spl196000 /*
59685678Spl196000 * NOTE: We send command only when slots availabe, so should never
59695678Spl196000 * reach here.
59705678Spl196000 */
59715678Spl196000 if (rval != AACOK) {
59725678Spl196000 AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
59735678Spl196000 if (acp->pkt) {
59745678Spl196000 acp->pkt->pkt_state &= ~STATE_SENT_CMD;
59755678Spl196000 aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
59765678Spl196000 }
59775678Spl196000 aac_end_io(softs, acp);
59785678Spl196000 if (!(acp->flags & (AAC_CMD_NO_INTR | AAC_CMD_NO_CB)))
59795678Spl196000 ddi_trigger_softintr(softs->softint_id);
59805678Spl196000 }
59815678Spl196000 }
59825678Spl196000
59835678Spl196000 static void
aac_start_waitq(struct aac_softstate * softs,struct aac_cmd_queue * q)59845678Spl196000 aac_start_waitq(struct aac_softstate *softs, struct aac_cmd_queue *q)
59855678Spl196000 {
59865678Spl196000 struct aac_cmd *acp, *next_acp;
59875678Spl196000
59885678Spl196000 /* Serve as many waiting io's as possible */
59895678Spl196000 for (acp = q->q_head; acp; acp = next_acp) {
59905678Spl196000 next_acp = acp->next;
59915678Spl196000 if (aac_bind_io(softs, acp) == AACOK) {
59925678Spl196000 aac_cmd_delete(q, acp);
59935678Spl196000 aac_start_io(softs, acp);
59945678Spl196000 }
59955678Spl196000 if (softs->free_io_slot_head == NULL)
59965678Spl196000 break;
59975678Spl196000 }
59985678Spl196000 }
59995678Spl196000
60005678Spl196000 static void
aac_start_waiting_io(struct aac_softstate * softs)60015678Spl196000 aac_start_waiting_io(struct aac_softstate *softs)
60025678Spl196000 {
60035678Spl196000 /*
60045678Spl196000 * Sync FIB io is served before async FIB io so that io requests
60055678Spl196000 * sent by interactive userland commands get responded asap.
60065678Spl196000 */
60075678Spl196000 if (softs->q_wait[AAC_CMDQ_SYNC].q_head)
60085678Spl196000 aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_SYNC]);
60095678Spl196000 if (softs->q_wait[AAC_CMDQ_ASYNC].q_head)
60105678Spl196000 aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_ASYNC]);
60115678Spl196000 }
60125678Spl196000
60135678Spl196000 static void
aac_drain_comp_q(struct aac_softstate * softs)60145678Spl196000 aac_drain_comp_q(struct aac_softstate *softs)
60155678Spl196000 {
60165678Spl196000 struct aac_cmd *acp;
60175678Spl196000 struct scsi_pkt *pkt;
60185678Spl196000
60195678Spl196000 /*CONSTCOND*/
60205678Spl196000 while (1) {
60215678Spl196000 mutex_enter(&softs->q_comp_mutex);
60225678Spl196000 acp = aac_cmd_dequeue(&softs->q_comp);
60235678Spl196000 mutex_exit(&softs->q_comp_mutex);
60245678Spl196000 if (acp != NULL) {
60255678Spl196000 ASSERT(acp->pkt != NULL);
60265678Spl196000 pkt = acp->pkt;
60275678Spl196000
60285678Spl196000 if (pkt->pkt_reason == CMD_CMPLT) {
60295678Spl196000 /*
60305678Spl196000 * Consistent packets need to be sync'ed first
60315678Spl196000 */
60325678Spl196000 if ((acp->flags & AAC_CMD_CONSISTENT) &&
60335678Spl196000 (acp->flags & AAC_CMD_BUF_READ)) {
60345678Spl196000 if (aac_dma_sync_ac(acp) != AACOK) {
60355678Spl196000 ddi_fm_service_impact(
60365678Spl196000 softs->devinfo_p,
60375678Spl196000 DDI_SERVICE_UNAFFECTED);
60385678Spl196000 pkt->pkt_reason = CMD_TRAN_ERR;
60395678Spl196000 pkt->pkt_statistics = 0;
60405678Spl196000 }
60415678Spl196000 }
60425678Spl196000 if ((aac_check_acc_handle(softs-> \
60435678Spl196000 comm_space_acc_handle) != DDI_SUCCESS) ||
60445678Spl196000 (aac_check_acc_handle(softs-> \
60455678Spl196000 pci_mem_handle) != DDI_SUCCESS)) {
60465678Spl196000 ddi_fm_service_impact(softs->devinfo_p,
60475678Spl196000 DDI_SERVICE_UNAFFECTED);
60485678Spl196000 ddi_fm_acc_err_clear(softs-> \
60495678Spl196000 pci_mem_handle, DDI_FME_VER0);
60505678Spl196000 pkt->pkt_reason = CMD_TRAN_ERR;
60515678Spl196000 pkt->pkt_statistics = 0;
60525678Spl196000 }
60535678Spl196000 if (aac_check_dma_handle(softs-> \
60545678Spl196000 comm_space_dma_handle) != DDI_SUCCESS) {
60555678Spl196000 ddi_fm_service_impact(softs->devinfo_p,
60565678Spl196000 DDI_SERVICE_UNAFFECTED);
60575678Spl196000 pkt->pkt_reason = CMD_TRAN_ERR;
60585678Spl196000 pkt->pkt_statistics = 0;
60595678Spl196000 }
60605678Spl196000 }
60619106SSrivijitha.Dugganapalli@Sun.COM scsi_hba_pkt_comp(pkt);
60625678Spl196000 } else {
60635678Spl196000 break;
60645678Spl196000 }
60655678Spl196000 }
60665678Spl196000 }
60675678Spl196000
60685678Spl196000 static int
aac_alloc_fib(struct aac_softstate * softs,struct aac_slot * slotp)60695678Spl196000 aac_alloc_fib(struct aac_softstate *softs, struct aac_slot *slotp)
60705678Spl196000 {
60715678Spl196000 size_t rlen;
60725678Spl196000 ddi_dma_cookie_t cookie;
60735678Spl196000 uint_t cookien;
60745678Spl196000
60755678Spl196000 /* Allocate FIB dma resource */
60765678Spl196000 if (ddi_dma_alloc_handle(
60775678Spl196000 softs->devinfo_p,
60785678Spl196000 &softs->addr_dma_attr,
60795678Spl196000 DDI_DMA_SLEEP,
60805678Spl196000 NULL,
60815678Spl196000 &slotp->fib_dma_handle) != DDI_SUCCESS) {
60825678Spl196000 AACDB_PRINT(softs, CE_WARN,
60835678Spl196000 "Cannot alloc dma handle for slot fib area");
60845678Spl196000 goto error;
60855678Spl196000 }
60865678Spl196000 if (ddi_dma_mem_alloc(
60875678Spl196000 slotp->fib_dma_handle,
60885678Spl196000 softs->aac_max_fib_size,
60897567SXin.Chen@Sun.COM &softs->acc_attr,
60905678Spl196000 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
60915678Spl196000 DDI_DMA_SLEEP,
60925678Spl196000 NULL,
60935678Spl196000 (caddr_t *)&slotp->fibp,
60945678Spl196000 &rlen,
60955678Spl196000 &slotp->fib_acc_handle) != DDI_SUCCESS) {
60965678Spl196000 AACDB_PRINT(softs, CE_WARN,
60975678Spl196000 "Cannot alloc mem for slot fib area");
60985678Spl196000 goto error;
60995678Spl196000 }
61005678Spl196000 if (ddi_dma_addr_bind_handle(
61015678Spl196000 slotp->fib_dma_handle,
61025678Spl196000 NULL,
61035678Spl196000 (caddr_t)slotp->fibp,
61045678Spl196000 softs->aac_max_fib_size,
61055678Spl196000 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
61065678Spl196000 DDI_DMA_SLEEP,
61075678Spl196000 NULL,
61085678Spl196000 &cookie,
61095678Spl196000 &cookien) != DDI_DMA_MAPPED) {
61105678Spl196000 AACDB_PRINT(softs, CE_WARN,
61115678Spl196000 "dma bind failed for slot fib area");
61125678Spl196000 goto error;
61135678Spl196000 }
61145678Spl196000
61155678Spl196000 /* Check dma handles allocated in fib attach */
61165678Spl196000 if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS) {
61175678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
61185678Spl196000 goto error;
61195678Spl196000 }
61205678Spl196000
61215678Spl196000 /* Check acc handles allocated in fib attach */
61225678Spl196000 if (aac_check_acc_handle(slotp->fib_acc_handle) != DDI_SUCCESS) {
61235678Spl196000 ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
61245678Spl196000 goto error;
61255678Spl196000 }
61265678Spl196000
61275678Spl196000 slotp->fib_phyaddr = cookie.dmac_laddress;
61285678Spl196000 return (AACOK);
61295678Spl196000
61305678Spl196000 error:
61315678Spl196000 if (slotp->fib_acc_handle) {
61325678Spl196000 ddi_dma_mem_free(&slotp->fib_acc_handle);
61335678Spl196000 slotp->fib_acc_handle = NULL;
61345678Spl196000 }
61355678Spl196000 if (slotp->fib_dma_handle) {
61365678Spl196000 ddi_dma_free_handle(&slotp->fib_dma_handle);
61375678Spl196000 slotp->fib_dma_handle = NULL;
61385678Spl196000 }
61395678Spl196000 return (AACERR);
61405678Spl196000 }
61415678Spl196000
61425678Spl196000 static void
aac_free_fib(struct aac_slot * slotp)61435678Spl196000 aac_free_fib(struct aac_slot *slotp)
61445678Spl196000 {
61455678Spl196000 (void) ddi_dma_unbind_handle(slotp->fib_dma_handle);
61465678Spl196000 ddi_dma_mem_free(&slotp->fib_acc_handle);
61475678Spl196000 slotp->fib_acc_handle = NULL;
61485678Spl196000 ddi_dma_free_handle(&slotp->fib_dma_handle);
61495678Spl196000 slotp->fib_dma_handle = NULL;
61505678Spl196000 slotp->fib_phyaddr = 0;
61515678Spl196000 }
61525678Spl196000
61535678Spl196000 static void
aac_alloc_fibs(struct aac_softstate * softs)61545678Spl196000 aac_alloc_fibs(struct aac_softstate *softs)
61555678Spl196000 {
61565678Spl196000 int i;
61575678Spl196000 struct aac_slot *slotp;
61585678Spl196000
61595678Spl196000 for (i = 0; i < softs->total_slots &&
61605678Spl196000 softs->total_fibs < softs->total_slots; i++) {
61615678Spl196000 slotp = &(softs->io_slot[i]);
61625678Spl196000 if (slotp->fib_phyaddr)
61635678Spl196000 continue;
61645678Spl196000 if (aac_alloc_fib(softs, slotp) != AACOK)
61655678Spl196000 break;
61665678Spl196000
61675678Spl196000 /* Insert the slot to the free slot list */
61685678Spl196000 aac_release_slot(softs, slotp);
61695678Spl196000 softs->total_fibs++;
61705678Spl196000 }
61715678Spl196000 }
61725678Spl196000
61735678Spl196000 static void
aac_destroy_fibs(struct aac_softstate * softs)61745678Spl196000 aac_destroy_fibs(struct aac_softstate *softs)
61755678Spl196000 {
61765678Spl196000 struct aac_slot *slotp;
61775678Spl196000
61785678Spl196000 while ((slotp = softs->free_io_slot_head) != NULL) {
61795678Spl196000 ASSERT(slotp->fib_phyaddr);
61805678Spl196000 softs->free_io_slot_head = slotp->next;
61815678Spl196000 aac_free_fib(slotp);
61825678Spl196000 ASSERT(slotp->index == (slotp - softs->io_slot));
61835678Spl196000 softs->total_fibs--;
61845678Spl196000 }
61855678Spl196000 ASSERT(softs->total_fibs == 0);
61865678Spl196000 }
61875678Spl196000
61885678Spl196000 static int
aac_create_slots(struct aac_softstate * softs)61895678Spl196000 aac_create_slots(struct aac_softstate *softs)
61905678Spl196000 {
61915678Spl196000 int i;
61925678Spl196000
61935678Spl196000 softs->total_slots = softs->aac_max_fibs;
61945678Spl196000 softs->io_slot = kmem_zalloc(sizeof (struct aac_slot) * \
61955678Spl196000 softs->total_slots, KM_SLEEP);
61965678Spl196000 if (softs->io_slot == NULL) {
61975678Spl196000 AACDB_PRINT(softs, CE_WARN, "Cannot allocate slot");
61985678Spl196000 return (AACERR);
61995678Spl196000 }
62005678Spl196000 for (i = 0; i < softs->total_slots; i++)
62015678Spl196000 softs->io_slot[i].index = i;
62025678Spl196000 softs->free_io_slot_head = NULL;
62035678Spl196000 softs->total_fibs = 0;
62045678Spl196000 return (AACOK);
62055678Spl196000 }
62065678Spl196000
62075678Spl196000 static void
aac_destroy_slots(struct aac_softstate * softs)62085678Spl196000 aac_destroy_slots(struct aac_softstate *softs)
62095678Spl196000 {
62105678Spl196000 ASSERT(softs->free_io_slot_head == NULL);
62115678Spl196000
62125678Spl196000 kmem_free(softs->io_slot, sizeof (struct aac_slot) * \
62135678Spl196000 softs->total_slots);
62145678Spl196000 softs->io_slot = NULL;
62155678Spl196000 softs->total_slots = 0;
62165678Spl196000 }
62175678Spl196000
62185678Spl196000 struct aac_slot *
aac_get_slot(struct aac_softstate * softs)62195678Spl196000 aac_get_slot(struct aac_softstate *softs)
62205678Spl196000 {
62215678Spl196000 struct aac_slot *slotp;
62225678Spl196000
62235678Spl196000 if ((slotp = softs->free_io_slot_head) != NULL) {
62245678Spl196000 softs->free_io_slot_head = slotp->next;
62255678Spl196000 slotp->next = NULL;
62265678Spl196000 }
62275678Spl196000 return (slotp);
62285678Spl196000 }
62295678Spl196000
62305678Spl196000 static void
aac_release_slot(struct aac_softstate * softs,struct aac_slot * slotp)62315678Spl196000 aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
62325678Spl196000 {
62335678Spl196000 ASSERT((slotp->index >= 0) && (slotp->index < softs->total_slots));
62345678Spl196000 ASSERT(slotp == &softs->io_slot[slotp->index]);
62355678Spl196000
62365678Spl196000 slotp->acp = NULL;
62375678Spl196000 slotp->next = softs->free_io_slot_head;
62385678Spl196000 softs->free_io_slot_head = slotp;
62395678Spl196000 }
62405678Spl196000
62415678Spl196000 int
aac_do_io(struct aac_softstate * softs,struct aac_cmd * acp)62425678Spl196000 aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
62435678Spl196000 {
62445678Spl196000 if (aac_bind_io(softs, acp) == AACOK)
62455678Spl196000 aac_start_io(softs, acp);
62465678Spl196000 else
62475678Spl196000 aac_cmd_enqueue(&softs->q_wait[AAC_CMDQ(acp)], acp);
62485678Spl196000
62495678Spl196000 if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR)))
62505678Spl196000 return (TRAN_ACCEPT);
62515678Spl196000 /*
62525678Spl196000 * Because sync FIB is always 512 bytes and used for critical
62535678Spl196000 * functions, async FIB is used for poll IO.
62545678Spl196000 */
62555678Spl196000 if (acp->flags & AAC_CMD_NO_INTR) {
62565678Spl196000 if (aac_do_poll_io(softs, acp) == AACOK)
62575678Spl196000 return (TRAN_ACCEPT);
62585678Spl196000 } else {
62595678Spl196000 if (aac_do_sync_io(softs, acp) == AACOK)
62605678Spl196000 return (TRAN_ACCEPT);
62615678Spl196000 }
62625678Spl196000 return (TRAN_BADPKT);
62635678Spl196000 }
62645678Spl196000
62655678Spl196000 static int
aac_do_poll_io(struct aac_softstate * softs,struct aac_cmd * acp)62665678Spl196000 aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
62675678Spl196000 {
62685678Spl196000 int (*intr_handler)(struct aac_softstate *);
62695678Spl196000
62705678Spl196000 /*
62715678Spl196000 * Interrupt is disabled, we have to poll the adapter by ourselves.
62725678Spl196000 */
62735678Spl196000 intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
62745678Spl196000 aac_process_intr_new : aac_process_intr_old;
62755678Spl196000 while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))) {
62765678Spl196000 int i = AAC_POLL_TIME * 1000;
62775678Spl196000
62785678Spl196000 AAC_BUSYWAIT((intr_handler(softs) != AAC_DB_RESPONSE_READY), i);
62795678Spl196000 if (i == 0)
62807567SXin.Chen@Sun.COM aac_cmd_timeout(softs, acp);
62815678Spl196000 }
62825678Spl196000
62835678Spl196000 ddi_trigger_softintr(softs->softint_id);
62845678Spl196000
62855678Spl196000 if ((acp->flags & AAC_CMD_CMPLT) && !(acp->flags & AAC_CMD_ERR))
62865678Spl196000 return (AACOK);
62875678Spl196000 return (AACERR);
62885678Spl196000 }
62895678Spl196000
62905678Spl196000 static int
aac_do_sync_io(struct aac_softstate * softs,struct aac_cmd * acp)62915678Spl196000 aac_do_sync_io(struct aac_softstate *softs, struct aac_cmd *acp)
62925678Spl196000 {
62935678Spl196000 ASSERT(softs && acp);
62945678Spl196000
62955678Spl196000 while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
62965678Spl196000 cv_wait(&softs->event, &softs->io_lock);
62975678Spl196000
62985678Spl196000 if (acp->flags & AAC_CMD_CMPLT)
62995678Spl196000 return (AACOK);
63005678Spl196000 return (AACERR);
63015678Spl196000 }
63025678Spl196000
63035678Spl196000 static int
aac_dma_sync_ac(struct aac_cmd * acp)63045678Spl196000 aac_dma_sync_ac(struct aac_cmd *acp)
63055678Spl196000 {
63065678Spl196000 if (acp->buf_dma_handle) {
63075678Spl196000 if (acp->flags & AAC_CMD_BUF_WRITE) {
63085678Spl196000 if (acp->abp != NULL)
63095678Spl196000 ddi_rep_put8(acp->abh,
63105678Spl196000 (uint8_t *)acp->bp->b_un.b_addr,
63115678Spl196000 (uint8_t *)acp->abp, acp->bp->b_bcount,
63125678Spl196000 DDI_DEV_AUTOINCR);
63135678Spl196000 (void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
63145678Spl196000 DDI_DMA_SYNC_FORDEV);
63155678Spl196000 } else {
63165678Spl196000 (void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
63175678Spl196000 DDI_DMA_SYNC_FORCPU);
63185678Spl196000 if (aac_check_dma_handle(acp->buf_dma_handle) !=
63195678Spl196000 DDI_SUCCESS)
63205678Spl196000 return (AACERR);
63215678Spl196000 if (acp->abp != NULL)
63225678Spl196000 ddi_rep_get8(acp->abh,
63235678Spl196000 (uint8_t *)acp->bp->b_un.b_addr,
63245678Spl196000 (uint8_t *)acp->abp, acp->bp->b_bcount,
63255678Spl196000 DDI_DEV_AUTOINCR);
63265678Spl196000 }
63275678Spl196000 }
63285678Spl196000 return (AACOK);
63295678Spl196000 }
63305678Spl196000
63315678Spl196000 /*
633211964SXin.Chen@Sun.COM * Copy AIF from adapter to the empty AIF slot and inform AIF threads
633311964SXin.Chen@Sun.COM */
633411964SXin.Chen@Sun.COM static void
aac_save_aif(struct aac_softstate * softs,ddi_acc_handle_t acc,struct aac_fib * fibp0,int fib_size0)633511964SXin.Chen@Sun.COM aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
633611964SXin.Chen@Sun.COM struct aac_fib *fibp0, int fib_size0)
633711964SXin.Chen@Sun.COM {
633811964SXin.Chen@Sun.COM struct aac_fib *fibp; /* FIB in AIF queue */
633911964SXin.Chen@Sun.COM int fib_size;
634011964SXin.Chen@Sun.COM uint16_t fib_command;
634111964SXin.Chen@Sun.COM int current, next;
634211964SXin.Chen@Sun.COM
634311964SXin.Chen@Sun.COM /* Ignore non AIF messages */
634411964SXin.Chen@Sun.COM fib_command = ddi_get16(acc, &fibp0->Header.Command);
634511964SXin.Chen@Sun.COM if (fib_command != AifRequest) {
634611964SXin.Chen@Sun.COM cmn_err(CE_WARN, "!Unknown command from controller");
634711964SXin.Chen@Sun.COM return;
634811964SXin.Chen@Sun.COM }
634911964SXin.Chen@Sun.COM
635011964SXin.Chen@Sun.COM mutex_enter(&softs->aifq_mutex);
635111964SXin.Chen@Sun.COM
635211964SXin.Chen@Sun.COM /* Save AIF */
635311964SXin.Chen@Sun.COM fibp = &softs->aifq[softs->aifq_idx].d;
635411964SXin.Chen@Sun.COM fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
635511964SXin.Chen@Sun.COM ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
635611964SXin.Chen@Sun.COM DDI_DEV_AUTOINCR);
635711964SXin.Chen@Sun.COM
635811964SXin.Chen@Sun.COM if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
635911964SXin.Chen@Sun.COM ddi_fm_service_impact(softs->devinfo_p,
636011964SXin.Chen@Sun.COM DDI_SERVICE_UNAFFECTED);
636111964SXin.Chen@Sun.COM mutex_exit(&softs->aifq_mutex);
636211964SXin.Chen@Sun.COM return;
636311964SXin.Chen@Sun.COM }
636411964SXin.Chen@Sun.COM
636511964SXin.Chen@Sun.COM AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
636611964SXin.Chen@Sun.COM
636711964SXin.Chen@Sun.COM /* Modify AIF contexts */
636811964SXin.Chen@Sun.COM current = softs->aifq_idx;
636911964SXin.Chen@Sun.COM next = (current + 1) % AAC_AIFQ_LENGTH;
637011964SXin.Chen@Sun.COM if (next == 0) {
637111964SXin.Chen@Sun.COM struct aac_fib_context *ctx_p;
637211964SXin.Chen@Sun.COM
637311964SXin.Chen@Sun.COM softs->aifq_wrap = 1;
637411964SXin.Chen@Sun.COM for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
637511964SXin.Chen@Sun.COM if (next == ctx_p->ctx_idx) {
637611964SXin.Chen@Sun.COM ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
637711964SXin.Chen@Sun.COM } else if (current == ctx_p->ctx_idx &&
637811964SXin.Chen@Sun.COM (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
637911964SXin.Chen@Sun.COM ctx_p->ctx_idx = next;
638011964SXin.Chen@Sun.COM ctx_p->ctx_overrun++;
638111964SXin.Chen@Sun.COM }
638211964SXin.Chen@Sun.COM }
638311964SXin.Chen@Sun.COM }
638411964SXin.Chen@Sun.COM softs->aifq_idx = next;
638511964SXin.Chen@Sun.COM
638611964SXin.Chen@Sun.COM /* Wakeup AIF threads */
638711964SXin.Chen@Sun.COM cv_broadcast(&softs->aifq_cv);
638811964SXin.Chen@Sun.COM mutex_exit(&softs->aifq_mutex);
638911964SXin.Chen@Sun.COM
639011964SXin.Chen@Sun.COM /* Wakeup event thread to handle aif */
639111964SXin.Chen@Sun.COM aac_event_disp(softs, AAC_EVENT_AIF);
639211964SXin.Chen@Sun.COM }
639311964SXin.Chen@Sun.COM
639411964SXin.Chen@Sun.COM static int
aac_return_aif_common(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)639511964SXin.Chen@Sun.COM aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
639611964SXin.Chen@Sun.COM struct aac_fib **fibpp)
639711964SXin.Chen@Sun.COM {
639811964SXin.Chen@Sun.COM int current;
639911964SXin.Chen@Sun.COM
640011964SXin.Chen@Sun.COM current = ctx->ctx_idx;
640111964SXin.Chen@Sun.COM if (current == softs->aifq_idx &&
640211964SXin.Chen@Sun.COM !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
640311964SXin.Chen@Sun.COM return (EAGAIN); /* Empty */
640411964SXin.Chen@Sun.COM
640511964SXin.Chen@Sun.COM *fibpp = &softs->aifq[current].d;
640611964SXin.Chen@Sun.COM
640711964SXin.Chen@Sun.COM ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
640811964SXin.Chen@Sun.COM ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
640911964SXin.Chen@Sun.COM return (0);
641011964SXin.Chen@Sun.COM }
641111964SXin.Chen@Sun.COM
641211964SXin.Chen@Sun.COM int
aac_return_aif(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)641311964SXin.Chen@Sun.COM aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
641411964SXin.Chen@Sun.COM struct aac_fib **fibpp)
641511964SXin.Chen@Sun.COM {
641611964SXin.Chen@Sun.COM int rval;
641711964SXin.Chen@Sun.COM
641811964SXin.Chen@Sun.COM mutex_enter(&softs->aifq_mutex);
641911964SXin.Chen@Sun.COM rval = aac_return_aif_common(softs, ctx, fibpp);
642011964SXin.Chen@Sun.COM mutex_exit(&softs->aifq_mutex);
642111964SXin.Chen@Sun.COM return (rval);
642211964SXin.Chen@Sun.COM }
642311964SXin.Chen@Sun.COM
642411964SXin.Chen@Sun.COM int
aac_return_aif_wait(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)642511964SXin.Chen@Sun.COM aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
642611964SXin.Chen@Sun.COM struct aac_fib **fibpp)
642711964SXin.Chen@Sun.COM {
642811964SXin.Chen@Sun.COM int rval;
642911964SXin.Chen@Sun.COM
643011964SXin.Chen@Sun.COM mutex_enter(&softs->aifq_mutex);
643111964SXin.Chen@Sun.COM rval = aac_return_aif_common(softs, ctx, fibpp);
643211964SXin.Chen@Sun.COM if (rval == EAGAIN) {
643311964SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
643411964SXin.Chen@Sun.COM rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
643511964SXin.Chen@Sun.COM }
643611964SXin.Chen@Sun.COM mutex_exit(&softs->aifq_mutex);
643711964SXin.Chen@Sun.COM return ((rval > 0) ? 0 : EINTR);
643811964SXin.Chen@Sun.COM }
643911964SXin.Chen@Sun.COM
644011964SXin.Chen@Sun.COM /*
64415678Spl196000 * The following function comes from Adaptec:
64425678Spl196000 *
64435678Spl196000 * When driver sees a particular event that means containers are changed, it
64445678Spl196000 * will rescan containers. However a change may not be complete until some
64455678Spl196000 * other event is received. For example, creating or deleting an array will
64465678Spl196000 * incur as many as six AifEnConfigChange events which would generate six
64475678Spl196000 * container rescans. To diminish rescans, driver set a flag to wait for
64485678Spl196000 * another particular event. When sees that events come in, it will do rescan.
64495678Spl196000 */
64505678Spl196000 static int
aac_handle_aif(struct aac_softstate * softs,struct aac_aif_command * aif)645111964SXin.Chen@Sun.COM aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
64525678Spl196000 {
64535678Spl196000 ddi_acc_handle_t acc = softs->comm_space_acc_handle;
64545678Spl196000 int en_type;
64555678Spl196000 int devcfg_needed;
6456*12408SZhongyan.Gu@Sun.COM int cid;
6457*12408SZhongyan.Gu@Sun.COM uint32_t bus_id, tgt_id;
6458*12408SZhongyan.Gu@Sun.COM enum aac_cfg_event event = AAC_CFG_NULL_EXIST;
645911964SXin.Chen@Sun.COM
64605678Spl196000 devcfg_needed = 0;
64615678Spl196000 en_type = LE_32((uint32_t)aif->data.EN.type);
64625678Spl196000
64635678Spl196000 switch (LE_32((uint32_t)aif->command)) {
64645678Spl196000 case AifCmdDriverNotify: {
6465*12408SZhongyan.Gu@Sun.COM cid = LE_32(aif->data.EN.data.ECC.container[0]);
64665678Spl196000
64675678Spl196000 switch (en_type) {
64685678Spl196000 case AifDenMorphComplete:
64695678Spl196000 case AifDenVolumeExtendComplete:
64707567SXin.Chen@Sun.COM if (AAC_DEV_IS_VALID(&softs->containers[cid].dev))
64715678Spl196000 softs->devcfg_wait_on = AifEnConfigChange;
64725678Spl196000 break;
64735678Spl196000 }
64745678Spl196000 if (softs->devcfg_wait_on == en_type)
64755678Spl196000 devcfg_needed = 1;
64765678Spl196000 break;
64775678Spl196000 }
64785678Spl196000
64795678Spl196000 case AifCmdEventNotify:
6480*12408SZhongyan.Gu@Sun.COM cid = LE_32(aif->data.EN.data.ECC.container[0]);
64815678Spl196000 switch (en_type) {
64825678Spl196000 case AifEnAddContainer:
64835678Spl196000 case AifEnDeleteContainer:
64845678Spl196000 softs->devcfg_wait_on = AifEnConfigChange;
64855678Spl196000 break;
64865678Spl196000 case AifEnContainerChange:
64875678Spl196000 if (!softs->devcfg_wait_on)
64885678Spl196000 softs->devcfg_wait_on = AifEnConfigChange;
64895678Spl196000 break;
64905678Spl196000 case AifEnContainerEvent:
64915678Spl196000 if (ddi_get32(acc, &aif-> \
64925678Spl196000 data.EN.data.ECE.eventType) == CT_PUP_MISSING_DRIVE)
64935678Spl196000 devcfg_needed = 1;
64945678Spl196000 break;
6495*12408SZhongyan.Gu@Sun.COM case AifEnAddJBOD:
6496*12408SZhongyan.Gu@Sun.COM if (!(softs->flags & AAC_FLAGS_JBOD))
6497*12408SZhongyan.Gu@Sun.COM return (AACERR);
6498*12408SZhongyan.Gu@Sun.COM event = AAC_CFG_ADD;
6499*12408SZhongyan.Gu@Sun.COM bus_id = (cid >> 24) & 0xf;
6500*12408SZhongyan.Gu@Sun.COM tgt_id = cid & 0xffff;
6501*12408SZhongyan.Gu@Sun.COM break;
6502*12408SZhongyan.Gu@Sun.COM case AifEnDeleteJBOD:
6503*12408SZhongyan.Gu@Sun.COM if (!(softs->flags & AAC_FLAGS_JBOD))
6504*12408SZhongyan.Gu@Sun.COM return (AACERR);
6505*12408SZhongyan.Gu@Sun.COM event = AAC_CFG_DELETE;
6506*12408SZhongyan.Gu@Sun.COM bus_id = (cid >> 24) & 0xf;
6507*12408SZhongyan.Gu@Sun.COM tgt_id = cid & 0xffff;
6508*12408SZhongyan.Gu@Sun.COM break;
65095678Spl196000 }
65105678Spl196000 if (softs->devcfg_wait_on == en_type)
65115678Spl196000 devcfg_needed = 1;
65125678Spl196000 break;
65135678Spl196000
65145678Spl196000 case AifCmdJobProgress:
65155678Spl196000 if (LE_32((uint32_t)aif->data.PR[0].jd.type) == AifJobCtrZero) {
65165678Spl196000 int pr_status;
65175678Spl196000 uint32_t pr_ftick, pr_ctick;
65185678Spl196000
65195678Spl196000 pr_status = LE_32((uint32_t)aif->data.PR[0].status);
65205678Spl196000 pr_ctick = LE_32(aif->data.PR[0].currentTick);
65215678Spl196000 pr_ftick = LE_32(aif->data.PR[0].finalTick);
65225678Spl196000
65235678Spl196000 if ((pr_ctick == pr_ftick) ||
65245678Spl196000 (pr_status == AifJobStsSuccess))
65255678Spl196000 softs->devcfg_wait_on = AifEnContainerChange;
65265678Spl196000 else if ((pr_ctick == 0) &&
65275678Spl196000 (pr_status == AifJobStsRunning))
65285678Spl196000 softs->devcfg_wait_on = AifEnContainerChange;
65295678Spl196000 }
65305678Spl196000 break;
65315678Spl196000 }
65325678Spl196000
65337567SXin.Chen@Sun.COM if (devcfg_needed) {
65347567SXin.Chen@Sun.COM softs->devcfg_wait_on = 0;
65355678Spl196000 (void) aac_probe_containers(softs);
65367567SXin.Chen@Sun.COM }
653711964SXin.Chen@Sun.COM
6538*12408SZhongyan.Gu@Sun.COM if (event != AAC_CFG_NULL_EXIST) {
6539*12408SZhongyan.Gu@Sun.COM ASSERT(en_type == AifEnAddJBOD || en_type == AifEnDeleteJBOD);
6540*12408SZhongyan.Gu@Sun.COM (void) aac_probe_jbod(softs,
6541*12408SZhongyan.Gu@Sun.COM AAC_P2VTGT(softs, bus_id, tgt_id), event);
6542*12408SZhongyan.Gu@Sun.COM }
65435678Spl196000 return (AACOK);
65445678Spl196000 }
65455678Spl196000
654611964SXin.Chen@Sun.COM
654711964SXin.Chen@Sun.COM /*
654811964SXin.Chen@Sun.COM * Check and handle AIF events
654911964SXin.Chen@Sun.COM */
655011964SXin.Chen@Sun.COM static void
aac_aif_event(struct aac_softstate * softs)655111964SXin.Chen@Sun.COM aac_aif_event(struct aac_softstate *softs)
655211964SXin.Chen@Sun.COM {
655311964SXin.Chen@Sun.COM struct aac_fib *fibp;
655411964SXin.Chen@Sun.COM
655511964SXin.Chen@Sun.COM /*CONSTCOND*/
655611964SXin.Chen@Sun.COM while (1) {
655711964SXin.Chen@Sun.COM if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
655811964SXin.Chen@Sun.COM break; /* No more AIFs to handle, end loop */
655911964SXin.Chen@Sun.COM
656011964SXin.Chen@Sun.COM /* AIF overrun, array create/delete may missed. */
656111964SXin.Chen@Sun.COM if (softs->aifctx.ctx_overrun) {
656211964SXin.Chen@Sun.COM softs->aifctx.ctx_overrun = 0;
656311964SXin.Chen@Sun.COM }
656411964SXin.Chen@Sun.COM
656511964SXin.Chen@Sun.COM /* AIF received, handle it */
656611964SXin.Chen@Sun.COM struct aac_aif_command *aifp =
656711964SXin.Chen@Sun.COM (struct aac_aif_command *)&fibp->data[0];
656811964SXin.Chen@Sun.COM uint32_t aif_command = LE_32((uint32_t)aifp->command);
656911964SXin.Chen@Sun.COM
657011964SXin.Chen@Sun.COM if (aif_command == AifCmdDriverNotify ||
657111964SXin.Chen@Sun.COM aif_command == AifCmdEventNotify ||
657211964SXin.Chen@Sun.COM aif_command == AifCmdJobProgress)
657311964SXin.Chen@Sun.COM (void) aac_handle_aif(softs, aifp);
657411964SXin.Chen@Sun.COM }
657511964SXin.Chen@Sun.COM }
657611964SXin.Chen@Sun.COM
65775678Spl196000 /*
65785678Spl196000 * Timeout recovery
65795678Spl196000 */
65807567SXin.Chen@Sun.COM /*ARGSUSED*/
65815678Spl196000 static void
aac_cmd_timeout(struct aac_softstate * softs,struct aac_cmd * acp)65827567SXin.Chen@Sun.COM aac_cmd_timeout(struct aac_softstate *softs, struct aac_cmd *acp)
65837567SXin.Chen@Sun.COM {
65847567SXin.Chen@Sun.COM #ifdef DEBUG
65857567SXin.Chen@Sun.COM acp->fib_flags |= AACDB_FLAGS_FIB_TIMEOUT;
65867567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "acp %p timed out", acp);
65877567SXin.Chen@Sun.COM AACDB_PRINT_FIB(softs, acp->slotp);
65887567SXin.Chen@Sun.COM #endif
65897567SXin.Chen@Sun.COM
65905678Spl196000 /*
65915678Spl196000 * Besides the firmware in unhealthy state, an overloaded
65925678Spl196000 * adapter may also incur pkt timeout.
65935678Spl196000 * There is a chance for an adapter with a slower IOP to take
65945678Spl196000 * longer than 60 seconds to process the commands, such as when
65955678Spl196000 * to perform IOs. So the adapter is doing a build on a RAID-5
65965678Spl196000 * while being required longer completion times should be
65975678Spl196000 * tolerated.
65985678Spl196000 */
65997567SXin.Chen@Sun.COM switch (aac_do_reset(softs)) {
66007567SXin.Chen@Sun.COM case AAC_IOP_RESET_SUCCEED:
66017567SXin.Chen@Sun.COM aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING, NULL, CMD_RESET);
66025678Spl196000 aac_start_waiting_io(softs);
66037567SXin.Chen@Sun.COM break;
66047567SXin.Chen@Sun.COM case AAC_IOP_RESET_FAILED:
66055678Spl196000 /* Abort all waiting cmds when adapter is dead */
66067567SXin.Chen@Sun.COM aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_TIMEOUT);
66077567SXin.Chen@Sun.COM break;
66087567SXin.Chen@Sun.COM case AAC_IOP_RESET_ABNORMAL:
66097567SXin.Chen@Sun.COM aac_start_waiting_io(softs);
66105678Spl196000 }
66115678Spl196000 }
66125678Spl196000
66135678Spl196000 /*
66145678Spl196000 * The following function comes from Adaptec:
66155678Spl196000 *
66165678Spl196000 * Time sync. command added to synchronize time with firmware every 30
66175678Spl196000 * minutes (required for correct AIF timestamps etc.)
66185678Spl196000 */
661911964SXin.Chen@Sun.COM static void
aac_sync_tick(struct aac_softstate * softs)66205678Spl196000 aac_sync_tick(struct aac_softstate *softs)
66215678Spl196000 {
662211348SZhongyan.Gu@Sun.COM ddi_acc_handle_t acc;
662311348SZhongyan.Gu@Sun.COM int rval;
662411348SZhongyan.Gu@Sun.COM
662511964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
662611964SXin.Chen@Sun.COM ASSERT(softs->time_sync <= softs->timebase);
662711964SXin.Chen@Sun.COM softs->time_sync = 0;
662811964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
662911964SXin.Chen@Sun.COM
663011348SZhongyan.Gu@Sun.COM /* Time sync. with firmware every AAC_SYNC_TICK */
663111348SZhongyan.Gu@Sun.COM (void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
663211348SZhongyan.Gu@Sun.COM acc = softs->sync_ac.slotp->fib_acc_handle;
663311348SZhongyan.Gu@Sun.COM
663411348SZhongyan.Gu@Sun.COM ddi_put32(acc, (void *)&softs->sync_ac.slotp->fibp->data[0],
663511348SZhongyan.Gu@Sun.COM ddi_get_time());
663611348SZhongyan.Gu@Sun.COM rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
663711348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(softs, &softs->sync_ac);
663811964SXin.Chen@Sun.COM
663911964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
664011964SXin.Chen@Sun.COM softs->time_sync = softs->timebase;
664111964SXin.Chen@Sun.COM if (rval != AACOK)
664211964SXin.Chen@Sun.COM /* retry shortly */
664311964SXin.Chen@Sun.COM softs->time_sync += aac_tick << 1;
664411964SXin.Chen@Sun.COM else
664511964SXin.Chen@Sun.COM softs->time_sync += AAC_SYNC_TICK;
664611964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
664711964SXin.Chen@Sun.COM }
664811964SXin.Chen@Sun.COM
664911964SXin.Chen@Sun.COM /*
665011964SXin.Chen@Sun.COM * Timeout checking and handling
665111964SXin.Chen@Sun.COM */
66525678Spl196000 static void
aac_daemon(struct aac_softstate * softs)665311964SXin.Chen@Sun.COM aac_daemon(struct aac_softstate *softs)
665411964SXin.Chen@Sun.COM {
665511964SXin.Chen@Sun.COM int time_out; /* set if timeout happened */
665611964SXin.Chen@Sun.COM int time_adjust;
665711964SXin.Chen@Sun.COM uint32_t softs_timebase;
665811964SXin.Chen@Sun.COM
665911964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
666011964SXin.Chen@Sun.COM ASSERT(softs->time_out <= softs->timebase);
666111964SXin.Chen@Sun.COM softs->time_out = 0;
666211964SXin.Chen@Sun.COM softs_timebase = softs->timebase;
666311964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
666411964SXin.Chen@Sun.COM
666511964SXin.Chen@Sun.COM /* Check slots for timeout pkts */
666611964SXin.Chen@Sun.COM time_adjust = 0;
666711964SXin.Chen@Sun.COM do {
666811964SXin.Chen@Sun.COM struct aac_cmd *acp;
666911964SXin.Chen@Sun.COM
667011964SXin.Chen@Sun.COM time_out = 0;
667111964SXin.Chen@Sun.COM for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
667211964SXin.Chen@Sun.COM if (acp->timeout == 0)
667311964SXin.Chen@Sun.COM continue;
667411964SXin.Chen@Sun.COM
667511964SXin.Chen@Sun.COM /*
667611964SXin.Chen@Sun.COM * If timeout happened, update outstanding cmds
667711964SXin.Chen@Sun.COM * to be checked later again.
667811964SXin.Chen@Sun.COM */
667911964SXin.Chen@Sun.COM if (time_adjust) {
668011964SXin.Chen@Sun.COM acp->timeout += time_adjust;
668111964SXin.Chen@Sun.COM continue;
668211964SXin.Chen@Sun.COM }
668311964SXin.Chen@Sun.COM
668411964SXin.Chen@Sun.COM if (acp->timeout <= softs_timebase) {
66857567SXin.Chen@Sun.COM aac_cmd_timeout(softs, acp);
668611964SXin.Chen@Sun.COM time_out = 1;
668711964SXin.Chen@Sun.COM time_adjust = aac_tick * drv_usectohz(1000000);
668811964SXin.Chen@Sun.COM break; /* timeout happened */
668911964SXin.Chen@Sun.COM } else {
669011964SXin.Chen@Sun.COM break; /* no timeout */
66915678Spl196000 }
669211964SXin.Chen@Sun.COM }
669311964SXin.Chen@Sun.COM } while (time_out);
669411964SXin.Chen@Sun.COM
669511964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
669611964SXin.Chen@Sun.COM softs->time_out = softs->timebase + aac_tick;
669711964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
669811964SXin.Chen@Sun.COM }
669911964SXin.Chen@Sun.COM
670011964SXin.Chen@Sun.COM /*
670111964SXin.Chen@Sun.COM * The event thread handles various tasks serially for the other parts of
670211964SXin.Chen@Sun.COM * the driver, so that they can run fast.
670311964SXin.Chen@Sun.COM */
670411964SXin.Chen@Sun.COM static void
aac_event_thread(struct aac_softstate * softs)670511964SXin.Chen@Sun.COM aac_event_thread(struct aac_softstate *softs)
670611964SXin.Chen@Sun.COM {
670711964SXin.Chen@Sun.COM int run = 1;
670811964SXin.Chen@Sun.COM
670911964SXin.Chen@Sun.COM DBCALLED(softs, 1);
671011964SXin.Chen@Sun.COM
671111964SXin.Chen@Sun.COM mutex_enter(&softs->ev_lock);
671211964SXin.Chen@Sun.COM while (run) {
671311964SXin.Chen@Sun.COM int events;
671411964SXin.Chen@Sun.COM
671511964SXin.Chen@Sun.COM if ((events = softs->events) == 0) {
671611964SXin.Chen@Sun.COM cv_wait(&softs->event_disp_cv, &softs->ev_lock);
671711964SXin.Chen@Sun.COM events = softs->events;
671811964SXin.Chen@Sun.COM }
671911964SXin.Chen@Sun.COM softs->events = 0;
672011964SXin.Chen@Sun.COM mutex_exit(&softs->ev_lock);
672111964SXin.Chen@Sun.COM
672211964SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
672311964SXin.Chen@Sun.COM if ((softs->state & AAC_STATE_RUN) &&
672411964SXin.Chen@Sun.COM (softs->state & AAC_STATE_DEAD) == 0) {
672511964SXin.Chen@Sun.COM if (events & AAC_EVENT_TIMEOUT)
672611964SXin.Chen@Sun.COM aac_daemon(softs);
672711964SXin.Chen@Sun.COM if (events & AAC_EVENT_SYNCTICK)
672811964SXin.Chen@Sun.COM aac_sync_tick(softs);
672911964SXin.Chen@Sun.COM if (events & AAC_EVENT_AIF)
673011964SXin.Chen@Sun.COM aac_aif_event(softs);
673111964SXin.Chen@Sun.COM } else {
673211964SXin.Chen@Sun.COM run = 0;
673311964SXin.Chen@Sun.COM }
673411964SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
673511964SXin.Chen@Sun.COM
673611964SXin.Chen@Sun.COM mutex_enter(&softs->ev_lock);
673711964SXin.Chen@Sun.COM }
673811964SXin.Chen@Sun.COM
673911964SXin.Chen@Sun.COM cv_signal(&softs->event_wait_cv);
674011964SXin.Chen@Sun.COM mutex_exit(&softs->ev_lock);
674111964SXin.Chen@Sun.COM }
674211964SXin.Chen@Sun.COM
674311964SXin.Chen@Sun.COM /*
674411964SXin.Chen@Sun.COM * Internal timer. It is only responsbile for time counting and report time
674511964SXin.Chen@Sun.COM * related events. Events handling is done by aac_event_thread(), so that
674611964SXin.Chen@Sun.COM * the timer itself could be as precise as possible.
674711964SXin.Chen@Sun.COM */
674811964SXin.Chen@Sun.COM static void
aac_timer(void * arg)674911964SXin.Chen@Sun.COM aac_timer(void *arg)
675011964SXin.Chen@Sun.COM {
675111964SXin.Chen@Sun.COM struct aac_softstate *softs = arg;
675211964SXin.Chen@Sun.COM int events = 0;
675311964SXin.Chen@Sun.COM
675411964SXin.Chen@Sun.COM mutex_enter(&softs->time_mutex);
675511964SXin.Chen@Sun.COM
675611964SXin.Chen@Sun.COM /* If timer is being stopped, exit */
675711964SXin.Chen@Sun.COM if (softs->timeout_id) {
675811964SXin.Chen@Sun.COM softs->timeout_id = timeout(aac_timer, (void *)softs,
67595678Spl196000 (aac_tick * drv_usectohz(1000000)));
676011964SXin.Chen@Sun.COM } else {
676111964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
676211964SXin.Chen@Sun.COM return;
676311964SXin.Chen@Sun.COM }
676411964SXin.Chen@Sun.COM
676511964SXin.Chen@Sun.COM /* Time counting */
676611964SXin.Chen@Sun.COM softs->timebase += aac_tick;
676711964SXin.Chen@Sun.COM
676811964SXin.Chen@Sun.COM /* Check time related events */
676911964SXin.Chen@Sun.COM if (softs->time_out && softs->time_out <= softs->timebase)
677011964SXin.Chen@Sun.COM events |= AAC_EVENT_TIMEOUT;
677111964SXin.Chen@Sun.COM if (softs->time_sync && softs->time_sync <= softs->timebase)
677211964SXin.Chen@Sun.COM events |= AAC_EVENT_SYNCTICK;
677311964SXin.Chen@Sun.COM
677411964SXin.Chen@Sun.COM mutex_exit(&softs->time_mutex);
677511964SXin.Chen@Sun.COM
677611964SXin.Chen@Sun.COM if (events)
677711964SXin.Chen@Sun.COM aac_event_disp(softs, events);
677811964SXin.Chen@Sun.COM }
677911964SXin.Chen@Sun.COM
678011964SXin.Chen@Sun.COM /*
678111964SXin.Chen@Sun.COM * Dispatch events to daemon thread for handling
678211964SXin.Chen@Sun.COM */
678311964SXin.Chen@Sun.COM static void
aac_event_disp(struct aac_softstate * softs,int events)678411964SXin.Chen@Sun.COM aac_event_disp(struct aac_softstate *softs, int events)
678511964SXin.Chen@Sun.COM {
678611964SXin.Chen@Sun.COM mutex_enter(&softs->ev_lock);
678711964SXin.Chen@Sun.COM softs->events |= events;
678811964SXin.Chen@Sun.COM cv_broadcast(&softs->event_disp_cv);
678911964SXin.Chen@Sun.COM mutex_exit(&softs->ev_lock);
67905678Spl196000 }
67915678Spl196000
67925678Spl196000 /*
67935678Spl196000 * Architecture dependent functions
67945678Spl196000 */
67955678Spl196000 static int
aac_rx_get_fwstatus(struct aac_softstate * softs)67965678Spl196000 aac_rx_get_fwstatus(struct aac_softstate *softs)
67975678Spl196000 {
67985678Spl196000 return (PCI_MEM_GET32(softs, AAC_OMR0));
67995678Spl196000 }
68005678Spl196000
68015678Spl196000 static int
aac_rx_get_mailbox(struct aac_softstate * softs,int mb)68025678Spl196000 aac_rx_get_mailbox(struct aac_softstate *softs, int mb)
68035678Spl196000 {
68045678Spl196000 return (PCI_MEM_GET32(softs, AAC_RX_MAILBOX + mb * 4));
68055678Spl196000 }
68065678Spl196000
68075678Spl196000 static void
aac_rx_set_mailbox(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)68085678Spl196000 aac_rx_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
68095678Spl196000 uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
68105678Spl196000 {
68115678Spl196000 PCI_MEM_PUT32(softs, AAC_RX_MAILBOX, cmd);
68125678Spl196000 PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 4, arg0);
68135678Spl196000 PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 8, arg1);
68145678Spl196000 PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 12, arg2);
68155678Spl196000 PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 16, arg3);
68165678Spl196000 }
68175678Spl196000
68185678Spl196000 static int
aac_rkt_get_fwstatus(struct aac_softstate * softs)68195678Spl196000 aac_rkt_get_fwstatus(struct aac_softstate *softs)
68205678Spl196000 {
68215678Spl196000 return (PCI_MEM_GET32(softs, AAC_OMR0));
68225678Spl196000 }
68235678Spl196000
68245678Spl196000 static int
aac_rkt_get_mailbox(struct aac_softstate * softs,int mb)68255678Spl196000 aac_rkt_get_mailbox(struct aac_softstate *softs, int mb)
68265678Spl196000 {
68275678Spl196000 return (PCI_MEM_GET32(softs, AAC_RKT_MAILBOX + mb *4));
68285678Spl196000 }
68295678Spl196000
68305678Spl196000 static void
aac_rkt_set_mailbox(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)68315678Spl196000 aac_rkt_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
68325678Spl196000 uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
68335678Spl196000 {
68345678Spl196000 PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX, cmd);
68355678Spl196000 PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 4, arg0);
68365678Spl196000 PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 8, arg1);
68375678Spl196000 PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 12, arg2);
68385678Spl196000 PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 16, arg3);
68395678Spl196000 }
68405678Spl196000
68415678Spl196000 /*
68425678Spl196000 * cb_ops functions
68435678Spl196000 */
68445678Spl196000 static int
aac_open(dev_t * devp,int flag,int otyp,cred_t * cred)68455678Spl196000 aac_open(dev_t *devp, int flag, int otyp, cred_t *cred)
68465678Spl196000 {
68475678Spl196000 struct aac_softstate *softs;
68485678Spl196000 int minor0, minor;
68495678Spl196000 int instance;
68505678Spl196000
68515678Spl196000 DBCALLED(NULL, 2);
68525678Spl196000
68535678Spl196000 if (otyp != OTYP_BLK && otyp != OTYP_CHR)
68545678Spl196000 return (EINVAL);
68555678Spl196000
68565678Spl196000 minor0 = getminor(*devp);
68575678Spl196000 minor = AAC_SCSA_MINOR(minor0);
68585678Spl196000
68595678Spl196000 if (AAC_IS_SCSA_NODE(minor))
68605678Spl196000 return (scsi_hba_open(devp, flag, otyp, cred));
68615678Spl196000
68625678Spl196000 instance = MINOR2INST(minor0);
68635678Spl196000 if (instance >= AAC_MAX_ADAPTERS)
68645678Spl196000 return (ENXIO);
68655678Spl196000
68665678Spl196000 softs = ddi_get_soft_state(aac_softstatep, instance);
68675678Spl196000 if (softs == NULL)
68685678Spl196000 return (ENXIO);
68695678Spl196000
68705678Spl196000 return (0);
68715678Spl196000 }
68725678Spl196000
68735678Spl196000 /*ARGSUSED*/
68745678Spl196000 static int
aac_close(dev_t dev,int flag,int otyp,cred_t * cred)68755678Spl196000 aac_close(dev_t dev, int flag, int otyp, cred_t *cred)
68765678Spl196000 {
68775678Spl196000 int minor0, minor;
68785678Spl196000 int instance;
68795678Spl196000
68805678Spl196000 DBCALLED(NULL, 2);
68815678Spl196000
68825678Spl196000 if (otyp != OTYP_BLK && otyp != OTYP_CHR)
68835678Spl196000 return (EINVAL);
68845678Spl196000
68855678Spl196000 minor0 = getminor(dev);
68865678Spl196000 minor = AAC_SCSA_MINOR(minor0);
68875678Spl196000
68885678Spl196000 if (AAC_IS_SCSA_NODE(minor))
68895678Spl196000 return (scsi_hba_close(dev, flag, otyp, cred));
68905678Spl196000
68915678Spl196000 instance = MINOR2INST(minor0);
68925678Spl196000 if (instance >= AAC_MAX_ADAPTERS)
68935678Spl196000 return (ENXIO);
68945678Spl196000
68955678Spl196000 return (0);
68965678Spl196000 }
68975678Spl196000
68985678Spl196000 static int
aac_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)68995678Spl196000 aac_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
69005678Spl196000 int *rval_p)
69015678Spl196000 {
69025678Spl196000 struct aac_softstate *softs;
69035678Spl196000 int minor0, minor;
69045678Spl196000 int instance;
69055678Spl196000
69065678Spl196000 DBCALLED(NULL, 2);
69075678Spl196000
69085678Spl196000 if (drv_priv(cred_p) != 0)
69095678Spl196000 return (EPERM);
69105678Spl196000
69115678Spl196000 minor0 = getminor(dev);
69125678Spl196000 minor = AAC_SCSA_MINOR(minor0);
69135678Spl196000
69145678Spl196000 if (AAC_IS_SCSA_NODE(minor))
69155678Spl196000 return (scsi_hba_ioctl(dev, cmd, arg, flag, cred_p, rval_p));
69165678Spl196000
69175678Spl196000 instance = MINOR2INST(minor0);
69185678Spl196000 if (instance < AAC_MAX_ADAPTERS) {
69195678Spl196000 softs = ddi_get_soft_state(aac_softstatep, instance);
69205678Spl196000 return (aac_do_ioctl(softs, dev, cmd, arg, flag));
69215678Spl196000 }
69225678Spl196000 return (ENXIO);
69235678Spl196000 }
69245678Spl196000
69255678Spl196000 /*
69265678Spl196000 * The IO fault service error handling callback function
69275678Spl196000 */
69285678Spl196000 /*ARGSUSED*/
69295678Spl196000 static int
aac_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)69305678Spl196000 aac_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
69315678Spl196000 {
69325678Spl196000 /*
69335678Spl196000 * as the driver can always deal with an error in any dma or
69345678Spl196000 * access handle, we can just return the fme_status value.
69355678Spl196000 */
69365678Spl196000 pci_ereport_post(dip, err, NULL);
69375678Spl196000 return (err->fme_status);
69385678Spl196000 }
69395678Spl196000
69405678Spl196000 /*
69415678Spl196000 * aac_fm_init - initialize fma capabilities and register with IO
69425678Spl196000 * fault services.
69435678Spl196000 */
69445678Spl196000 static void
aac_fm_init(struct aac_softstate * softs)69455678Spl196000 aac_fm_init(struct aac_softstate *softs)
69465678Spl196000 {
69475678Spl196000 /*
69485678Spl196000 * Need to change iblock to priority for new MSI intr
69495678Spl196000 */
69505678Spl196000 ddi_iblock_cookie_t fm_ibc;
69515678Spl196000
69527567SXin.Chen@Sun.COM softs->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, softs->devinfo_p,
69537567SXin.Chen@Sun.COM DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
69547567SXin.Chen@Sun.COM DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
69557567SXin.Chen@Sun.COM DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
69567567SXin.Chen@Sun.COM
69575678Spl196000 /* Only register with IO Fault Services if we have some capability */
69585678Spl196000 if (softs->fm_capabilities) {
69595678Spl196000 /* Adjust access and dma attributes for FMA */
696011236SStephen.Hanson@Sun.COM softs->reg_attr.devacc_attr_access = DDI_FLAGERR_ACC;
69617567SXin.Chen@Sun.COM softs->addr_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
69627567SXin.Chen@Sun.COM softs->buf_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
69635678Spl196000
69645678Spl196000 /*
69655678Spl196000 * Register capabilities with IO Fault Services.
69665678Spl196000 * fm_capabilities will be updated to indicate
69675678Spl196000 * capabilities actually supported (not requested.)
69685678Spl196000 */
69695678Spl196000 ddi_fm_init(softs->devinfo_p, &softs->fm_capabilities, &fm_ibc);
69705678Spl196000
69715678Spl196000 /*
69725678Spl196000 * Initialize pci ereport capabilities if ereport
69735678Spl196000 * capable (should always be.)
69745678Spl196000 */
69755678Spl196000 if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
69765678Spl196000 DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
69775678Spl196000 pci_ereport_setup(softs->devinfo_p);
69785678Spl196000 }
69795678Spl196000
69805678Spl196000 /*
69815678Spl196000 * Register error callback if error callback capable.
69825678Spl196000 */
69835678Spl196000 if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
69845678Spl196000 ddi_fm_handler_register(softs->devinfo_p,
69855678Spl196000 aac_fm_error_cb, (void *) softs);
69865678Spl196000 }
69875678Spl196000 }
69885678Spl196000 }
69895678Spl196000
69905678Spl196000 /*
69915678Spl196000 * aac_fm_fini - Releases fma capabilities and un-registers with IO
69925678Spl196000 * fault services.
69935678Spl196000 */
69945678Spl196000 static void
aac_fm_fini(struct aac_softstate * softs)69955678Spl196000 aac_fm_fini(struct aac_softstate *softs)
69965678Spl196000 {
69975678Spl196000 /* Only unregister FMA capabilities if registered */
69985678Spl196000 if (softs->fm_capabilities) {
69995678Spl196000 /*
70005678Spl196000 * Un-register error callback if error callback capable.
70015678Spl196000 */
70025678Spl196000 if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
70035678Spl196000 ddi_fm_handler_unregister(softs->devinfo_p);
70045678Spl196000 }
70055678Spl196000
70065678Spl196000 /*
70075678Spl196000 * Release any resources allocated by pci_ereport_setup()
70085678Spl196000 */
70095678Spl196000 if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
70105678Spl196000 DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
70115678Spl196000 pci_ereport_teardown(softs->devinfo_p);
70125678Spl196000 }
70135678Spl196000
70145678Spl196000 /* Unregister from IO Fault Services */
70155678Spl196000 ddi_fm_fini(softs->devinfo_p);
70167567SXin.Chen@Sun.COM
70177567SXin.Chen@Sun.COM /* Adjust access and dma attributes for FMA */
701811236SStephen.Hanson@Sun.COM softs->reg_attr.devacc_attr_access = DDI_DEFAULT_ACC;
70197567SXin.Chen@Sun.COM softs->addr_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
70207567SXin.Chen@Sun.COM softs->buf_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
70215678Spl196000 }
70225678Spl196000 }
70235678Spl196000
70245678Spl196000 int
aac_check_acc_handle(ddi_acc_handle_t handle)70255678Spl196000 aac_check_acc_handle(ddi_acc_handle_t handle)
70265678Spl196000 {
70275678Spl196000 ddi_fm_error_t de;
70285678Spl196000
70295678Spl196000 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
70305678Spl196000 return (de.fme_status);
70315678Spl196000 }
70325678Spl196000
70335678Spl196000 int
aac_check_dma_handle(ddi_dma_handle_t handle)70345678Spl196000 aac_check_dma_handle(ddi_dma_handle_t handle)
70355678Spl196000 {
70365678Spl196000 ddi_fm_error_t de;
70375678Spl196000
70385678Spl196000 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
70395678Spl196000 return (de.fme_status);
70405678Spl196000 }
70415678Spl196000
70425678Spl196000 void
aac_fm_ereport(struct aac_softstate * softs,char * detail)70435678Spl196000 aac_fm_ereport(struct aac_softstate *softs, char *detail)
70445678Spl196000 {
70455678Spl196000 uint64_t ena;
70465678Spl196000 char buf[FM_MAX_CLASS];
70475678Spl196000
70485678Spl196000 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
70495678Spl196000 ena = fm_ena_generate(0, FM_ENA_FMT1);
70505678Spl196000 if (DDI_FM_EREPORT_CAP(softs->fm_capabilities)) {
70515678Spl196000 ddi_fm_ereport_post(softs->devinfo_p, buf, ena, DDI_NOSLEEP,
70525678Spl196000 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
70535678Spl196000 }
70545678Spl196000 }
70555678Spl196000
70567567SXin.Chen@Sun.COM /*
70577567SXin.Chen@Sun.COM * Autoconfiguration support
70587567SXin.Chen@Sun.COM */
70597567SXin.Chen@Sun.COM static int
aac_parse_devname(char * devnm,int * tgt,int * lun)70607567SXin.Chen@Sun.COM aac_parse_devname(char *devnm, int *tgt, int *lun)
70617567SXin.Chen@Sun.COM {
70627567SXin.Chen@Sun.COM char devbuf[SCSI_MAXNAMELEN];
70637567SXin.Chen@Sun.COM char *addr;
70647567SXin.Chen@Sun.COM char *p, *tp, *lp;
70657567SXin.Chen@Sun.COM long num;
70667567SXin.Chen@Sun.COM
70677567SXin.Chen@Sun.COM /* Parse dev name and address */
70687567SXin.Chen@Sun.COM (void) strcpy(devbuf, devnm);
70697567SXin.Chen@Sun.COM addr = "";
70707567SXin.Chen@Sun.COM for (p = devbuf; *p != '\0'; p++) {
70717567SXin.Chen@Sun.COM if (*p == '@') {
70727567SXin.Chen@Sun.COM addr = p + 1;
70737567SXin.Chen@Sun.COM *p = '\0';
70747567SXin.Chen@Sun.COM } else if (*p == ':') {
70757567SXin.Chen@Sun.COM *p = '\0';
70767567SXin.Chen@Sun.COM break;
70777567SXin.Chen@Sun.COM }
70787567SXin.Chen@Sun.COM }
70797567SXin.Chen@Sun.COM
70807567SXin.Chen@Sun.COM /* Parse taget and lun */
70817567SXin.Chen@Sun.COM for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
70827567SXin.Chen@Sun.COM if (*p == ',') {
70837567SXin.Chen@Sun.COM lp = p + 1;
70847567SXin.Chen@Sun.COM *p = '\0';
70857567SXin.Chen@Sun.COM break;
70867567SXin.Chen@Sun.COM }
70877567SXin.Chen@Sun.COM }
70887567SXin.Chen@Sun.COM if (tgt && tp) {
70897567SXin.Chen@Sun.COM if (ddi_strtol(tp, NULL, 0x10, &num))
70907567SXin.Chen@Sun.COM return (AACERR);
70917567SXin.Chen@Sun.COM *tgt = (int)num;
70927567SXin.Chen@Sun.COM }
70937567SXin.Chen@Sun.COM if (lun && lp) {
70947567SXin.Chen@Sun.COM if (ddi_strtol(lp, NULL, 0x10, &num))
70957567SXin.Chen@Sun.COM return (AACERR);
70967567SXin.Chen@Sun.COM *lun = (int)num;
70977567SXin.Chen@Sun.COM }
70987567SXin.Chen@Sun.COM return (AACOK);
70997567SXin.Chen@Sun.COM }
71007567SXin.Chen@Sun.COM
71017567SXin.Chen@Sun.COM static dev_info_t *
aac_find_child(struct aac_softstate * softs,uint16_t tgt,uint8_t lun)71027567SXin.Chen@Sun.COM aac_find_child(struct aac_softstate *softs, uint16_t tgt, uint8_t lun)
71037567SXin.Chen@Sun.COM {
71047567SXin.Chen@Sun.COM dev_info_t *child = NULL;
71057567SXin.Chen@Sun.COM char addr[SCSI_MAXNAMELEN];
71067567SXin.Chen@Sun.COM char tmp[MAXNAMELEN];
71077567SXin.Chen@Sun.COM
71087567SXin.Chen@Sun.COM if (tgt < AAC_MAX_LD) {
71097567SXin.Chen@Sun.COM if (lun == 0) {
71107567SXin.Chen@Sun.COM struct aac_device *dvp = &softs->containers[tgt].dev;
71117567SXin.Chen@Sun.COM
71127567SXin.Chen@Sun.COM child = dvp->dip;
71137567SXin.Chen@Sun.COM }
71147567SXin.Chen@Sun.COM } else {
71157567SXin.Chen@Sun.COM (void) sprintf(addr, "%x,%x", tgt, lun);
71167567SXin.Chen@Sun.COM for (child = ddi_get_child(softs->devinfo_p);
71177567SXin.Chen@Sun.COM child; child = ddi_get_next_sibling(child)) {
71187567SXin.Chen@Sun.COM /* We don't care about non-persistent node */
71197567SXin.Chen@Sun.COM if (ndi_dev_is_persistent_node(child) == 0)
71207567SXin.Chen@Sun.COM continue;
71217567SXin.Chen@Sun.COM
71227567SXin.Chen@Sun.COM if (aac_name_node(child, tmp, MAXNAMELEN) !=
71237567SXin.Chen@Sun.COM DDI_SUCCESS)
71247567SXin.Chen@Sun.COM continue;
71257567SXin.Chen@Sun.COM if (strcmp(addr, tmp) == 0)
71267567SXin.Chen@Sun.COM break;
71277567SXin.Chen@Sun.COM }
71287567SXin.Chen@Sun.COM }
71297567SXin.Chen@Sun.COM return (child);
71307567SXin.Chen@Sun.COM }
71317567SXin.Chen@Sun.COM
71327567SXin.Chen@Sun.COM static int
aac_config_child(struct aac_softstate * softs,struct scsi_device * sd,dev_info_t ** dipp)71337567SXin.Chen@Sun.COM aac_config_child(struct aac_softstate *softs, struct scsi_device *sd,
71347567SXin.Chen@Sun.COM dev_info_t **dipp)
71357567SXin.Chen@Sun.COM {
71367567SXin.Chen@Sun.COM char *nodename = NULL;
71377567SXin.Chen@Sun.COM char **compatible = NULL;
71387567SXin.Chen@Sun.COM int ncompatible = 0;
71397567SXin.Chen@Sun.COM char *childname;
71407567SXin.Chen@Sun.COM dev_info_t *ldip = NULL;
71417567SXin.Chen@Sun.COM int tgt = sd->sd_address.a_target;
71427567SXin.Chen@Sun.COM int lun = sd->sd_address.a_lun;
71437567SXin.Chen@Sun.COM int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
71447567SXin.Chen@Sun.COM int rval;
71457567SXin.Chen@Sun.COM
71467567SXin.Chen@Sun.COM DBCALLED(softs, 2);
71477567SXin.Chen@Sun.COM
71487567SXin.Chen@Sun.COM scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
71497567SXin.Chen@Sun.COM NULL, &nodename, &compatible, &ncompatible);
71507567SXin.Chen@Sun.COM if (nodename == NULL) {
71517567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN,
71527567SXin.Chen@Sun.COM "found no comptible driver for t%dL%d", tgt, lun);
71537567SXin.Chen@Sun.COM rval = NDI_FAILURE;
71547567SXin.Chen@Sun.COM goto finish;
71557567SXin.Chen@Sun.COM }
71567567SXin.Chen@Sun.COM childname = (softs->legacy && dtype == DTYPE_DIRECT) ? "sd" : nodename;
71577567SXin.Chen@Sun.COM
71587567SXin.Chen@Sun.COM /* Create dev node */
71597567SXin.Chen@Sun.COM rval = ndi_devi_alloc(softs->devinfo_p, childname, DEVI_SID_NODEID,
71607567SXin.Chen@Sun.COM &ldip);
71617567SXin.Chen@Sun.COM if (rval == NDI_SUCCESS) {
71627567SXin.Chen@Sun.COM if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
71637567SXin.Chen@Sun.COM != DDI_PROP_SUCCESS) {
71647567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "unable to create "
71657567SXin.Chen@Sun.COM "property for t%dL%d (target)", tgt, lun);
71667567SXin.Chen@Sun.COM rval = NDI_FAILURE;
71677567SXin.Chen@Sun.COM goto finish;
71687567SXin.Chen@Sun.COM }
71697567SXin.Chen@Sun.COM if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
71707567SXin.Chen@Sun.COM != DDI_PROP_SUCCESS) {
71717567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "unable to create "
71727567SXin.Chen@Sun.COM "property for t%dL%d (lun)", tgt, lun);
71737567SXin.Chen@Sun.COM rval = NDI_FAILURE;
71747567SXin.Chen@Sun.COM goto finish;
71757567SXin.Chen@Sun.COM }
71767567SXin.Chen@Sun.COM if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
71777567SXin.Chen@Sun.COM "compatible", compatible, ncompatible)
71787567SXin.Chen@Sun.COM != DDI_PROP_SUCCESS) {
71797567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "unable to create "
71807567SXin.Chen@Sun.COM "property for t%dL%d (compatible)", tgt, lun);
71817567SXin.Chen@Sun.COM rval = NDI_FAILURE;
71827567SXin.Chen@Sun.COM goto finish;
71837567SXin.Chen@Sun.COM }
71847567SXin.Chen@Sun.COM
71857567SXin.Chen@Sun.COM rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
71867567SXin.Chen@Sun.COM if (rval != NDI_SUCCESS) {
71877567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN, "unable to online t%dL%d",
71887567SXin.Chen@Sun.COM tgt, lun);
71897567SXin.Chen@Sun.COM ndi_prop_remove_all(ldip);
71907567SXin.Chen@Sun.COM (void) ndi_devi_free(ldip);
71917567SXin.Chen@Sun.COM }
71927567SXin.Chen@Sun.COM }
71937567SXin.Chen@Sun.COM finish:
71947567SXin.Chen@Sun.COM if (dipp)
71957567SXin.Chen@Sun.COM *dipp = ldip;
71967567SXin.Chen@Sun.COM
71977567SXin.Chen@Sun.COM scsi_hba_nodename_compatible_free(nodename, compatible);
71987567SXin.Chen@Sun.COM return (rval);
71997567SXin.Chen@Sun.COM }
72007567SXin.Chen@Sun.COM
72017567SXin.Chen@Sun.COM /*ARGSUSED*/
72027567SXin.Chen@Sun.COM static int
aac_probe_lun(struct aac_softstate * softs,struct scsi_device * sd)72037567SXin.Chen@Sun.COM aac_probe_lun(struct aac_softstate *softs, struct scsi_device *sd)
72047567SXin.Chen@Sun.COM {
72057567SXin.Chen@Sun.COM int tgt = sd->sd_address.a_target;
72067567SXin.Chen@Sun.COM int lun = sd->sd_address.a_lun;
72077567SXin.Chen@Sun.COM
72087567SXin.Chen@Sun.COM DBCALLED(softs, 2);
72097567SXin.Chen@Sun.COM
72107567SXin.Chen@Sun.COM if (tgt < AAC_MAX_LD) {
721111964SXin.Chen@Sun.COM enum aac_cfg_event event;
72127567SXin.Chen@Sun.COM
72137567SXin.Chen@Sun.COM if (lun == 0) {
72147567SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
721511964SXin.Chen@Sun.COM event = aac_probe_container(softs, tgt);
72167567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
721711964SXin.Chen@Sun.COM if ((event != AAC_CFG_NULL_NOEXIST) &&
721811964SXin.Chen@Sun.COM (event != AAC_CFG_DELETE)) {
72197567SXin.Chen@Sun.COM if (scsi_hba_probe(sd, NULL) ==
72207567SXin.Chen@Sun.COM SCSIPROBE_EXISTS)
72217567SXin.Chen@Sun.COM return (NDI_SUCCESS);
72227567SXin.Chen@Sun.COM }
72237567SXin.Chen@Sun.COM }
72247567SXin.Chen@Sun.COM return (NDI_FAILURE);
72257567SXin.Chen@Sun.COM } else {
72267567SXin.Chen@Sun.COM int dtype;
7227*12408SZhongyan.Gu@Sun.COM int qual; /* device qualifier */
72287567SXin.Chen@Sun.COM
72297567SXin.Chen@Sun.COM if (scsi_hba_probe(sd, NULL) != SCSIPROBE_EXISTS)
72307567SXin.Chen@Sun.COM return (NDI_FAILURE);
72317567SXin.Chen@Sun.COM
72327567SXin.Chen@Sun.COM dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
7233*12408SZhongyan.Gu@Sun.COM qual = dtype >> 5;
72347567SXin.Chen@Sun.COM
72357567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
72367567SXin.Chen@Sun.COM "Phys. device found: tgt %d dtype %d: %s",
72377567SXin.Chen@Sun.COM tgt, dtype, sd->sd_inq->inq_vid);
72387567SXin.Chen@Sun.COM
7239*12408SZhongyan.Gu@Sun.COM /* Only non-DASD and JBOD mode DASD are allowed exposed */
7240*12408SZhongyan.Gu@Sun.COM if (dtype == DTYPE_RODIRECT /* CDROM */ ||
7241*12408SZhongyan.Gu@Sun.COM dtype == DTYPE_SEQUENTIAL /* TAPE */ ||
7242*12408SZhongyan.Gu@Sun.COM dtype == DTYPE_ESI /* SES */) {
7243*12408SZhongyan.Gu@Sun.COM if (!(softs->flags & AAC_FLAGS_NONDASD))
7244*12408SZhongyan.Gu@Sun.COM return (NDI_FAILURE);
7245*12408SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE, "non-DASD %d found", tgt);
7246*12408SZhongyan.Gu@Sun.COM
7247*12408SZhongyan.Gu@Sun.COM } else if (dtype == DTYPE_DIRECT) {
7248*12408SZhongyan.Gu@Sun.COM if (!(softs->flags & AAC_FLAGS_JBOD) || qual != 0)
7249*12408SZhongyan.Gu@Sun.COM return (NDI_FAILURE);
7250*12408SZhongyan.Gu@Sun.COM AACDB_PRINT(softs, CE_NOTE, "JBOD DASD %d found", tgt);
7251*12408SZhongyan.Gu@Sun.COM }
7252*12408SZhongyan.Gu@Sun.COM
72537567SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
72547567SXin.Chen@Sun.COM softs->nondasds[AAC_PD(tgt)].dev.flags |= AAC_DFLAG_VALID;
72557567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
72567567SXin.Chen@Sun.COM return (NDI_SUCCESS);
72577567SXin.Chen@Sun.COM }
72587567SXin.Chen@Sun.COM }
72597567SXin.Chen@Sun.COM
72607567SXin.Chen@Sun.COM static int
aac_config_lun(struct aac_softstate * softs,uint16_t tgt,uint8_t lun,dev_info_t ** ldip)72617567SXin.Chen@Sun.COM aac_config_lun(struct aac_softstate *softs, uint16_t tgt, uint8_t lun,
72627567SXin.Chen@Sun.COM dev_info_t **ldip)
72637567SXin.Chen@Sun.COM {
72647567SXin.Chen@Sun.COM struct scsi_device sd;
72657567SXin.Chen@Sun.COM dev_info_t *child;
72667567SXin.Chen@Sun.COM int rval;
72677567SXin.Chen@Sun.COM
72687567SXin.Chen@Sun.COM DBCALLED(softs, 2);
72697567SXin.Chen@Sun.COM
72707567SXin.Chen@Sun.COM if ((child = aac_find_child(softs, tgt, lun)) != NULL) {
72717567SXin.Chen@Sun.COM if (ldip)
72727567SXin.Chen@Sun.COM *ldip = child;
72737567SXin.Chen@Sun.COM return (NDI_SUCCESS);
72747567SXin.Chen@Sun.COM }
72757567SXin.Chen@Sun.COM
72767567SXin.Chen@Sun.COM bzero(&sd, sizeof (struct scsi_device));
72777567SXin.Chen@Sun.COM sd.sd_address.a_hba_tran = softs->hba_tran;
72787567SXin.Chen@Sun.COM sd.sd_address.a_target = (uint16_t)tgt;
72797567SXin.Chen@Sun.COM sd.sd_address.a_lun = (uint8_t)lun;
72807567SXin.Chen@Sun.COM if ((rval = aac_probe_lun(softs, &sd)) == NDI_SUCCESS)
72817567SXin.Chen@Sun.COM rval = aac_config_child(softs, &sd, ldip);
728211348SZhongyan.Gu@Sun.COM /* scsi_unprobe is blank now. Free buffer manually */
728311348SZhongyan.Gu@Sun.COM if (sd.sd_inq) {
728411348SZhongyan.Gu@Sun.COM kmem_free(sd.sd_inq, SUN_INQSIZE);
728511348SZhongyan.Gu@Sun.COM sd.sd_inq = (struct scsi_inquiry *)NULL;
728611348SZhongyan.Gu@Sun.COM }
72877567SXin.Chen@Sun.COM return (rval);
72887567SXin.Chen@Sun.COM }
72897567SXin.Chen@Sun.COM
72907567SXin.Chen@Sun.COM static int
aac_config_tgt(struct aac_softstate * softs,int tgt)72917567SXin.Chen@Sun.COM aac_config_tgt(struct aac_softstate *softs, int tgt)
72927567SXin.Chen@Sun.COM {
72937567SXin.Chen@Sun.COM struct scsi_address ap;
72947567SXin.Chen@Sun.COM struct buf *bp = NULL;
72957567SXin.Chen@Sun.COM int buf_len = AAC_SCSI_RPTLUNS_HEAD_SIZE + AAC_SCSI_RPTLUNS_ADDR_SIZE;
72967567SXin.Chen@Sun.COM int list_len = 0;
72977567SXin.Chen@Sun.COM int lun_total = 0;
72987567SXin.Chen@Sun.COM dev_info_t *ldip;
72997567SXin.Chen@Sun.COM int i;
73007567SXin.Chen@Sun.COM
73017567SXin.Chen@Sun.COM ap.a_hba_tran = softs->hba_tran;
73027567SXin.Chen@Sun.COM ap.a_target = (uint16_t)tgt;
73037567SXin.Chen@Sun.COM ap.a_lun = 0;
73047567SXin.Chen@Sun.COM
73057567SXin.Chen@Sun.COM for (i = 0; i < 2; i++) {
73067567SXin.Chen@Sun.COM struct scsi_pkt *pkt;
73077567SXin.Chen@Sun.COM uchar_t *cdb;
73087567SXin.Chen@Sun.COM uchar_t *p;
73097567SXin.Chen@Sun.COM uint32_t data;
73107567SXin.Chen@Sun.COM
73117567SXin.Chen@Sun.COM if (bp == NULL) {
73127567SXin.Chen@Sun.COM if ((bp = scsi_alloc_consistent_buf(&ap, NULL,
73137567SXin.Chen@Sun.COM buf_len, B_READ, NULL_FUNC, NULL)) == NULL)
73147567SXin.Chen@Sun.COM return (AACERR);
73157567SXin.Chen@Sun.COM }
73167567SXin.Chen@Sun.COM if ((pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP5,
73177567SXin.Chen@Sun.COM sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT,
73187567SXin.Chen@Sun.COM NULL, NULL)) == NULL) {
73197567SXin.Chen@Sun.COM scsi_free_consistent_buf(bp);
73207567SXin.Chen@Sun.COM return (AACERR);
73217567SXin.Chen@Sun.COM }
73227567SXin.Chen@Sun.COM cdb = pkt->pkt_cdbp;
73237567SXin.Chen@Sun.COM bzero(cdb, CDB_GROUP5);
73247567SXin.Chen@Sun.COM cdb[0] = SCMD_REPORT_LUNS;
73257567SXin.Chen@Sun.COM
73267567SXin.Chen@Sun.COM /* Convert buffer len from local to LE_32 */
73277567SXin.Chen@Sun.COM data = buf_len;
73287567SXin.Chen@Sun.COM for (p = &cdb[9]; p > &cdb[5]; p--) {
73297567SXin.Chen@Sun.COM *p = data & 0xff;
73307567SXin.Chen@Sun.COM data >>= 8;
73317567SXin.Chen@Sun.COM }
73327567SXin.Chen@Sun.COM
73337567SXin.Chen@Sun.COM if (scsi_poll(pkt) < 0 ||
73347567SXin.Chen@Sun.COM ((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
73357567SXin.Chen@Sun.COM scsi_destroy_pkt(pkt);
73367567SXin.Chen@Sun.COM break;
73377567SXin.Chen@Sun.COM }
73387567SXin.Chen@Sun.COM
73397567SXin.Chen@Sun.COM /* Convert list_len from LE_32 to local */
73407567SXin.Chen@Sun.COM for (p = (uchar_t *)bp->b_un.b_addr;
73417567SXin.Chen@Sun.COM p < (uchar_t *)bp->b_un.b_addr + 4; p++) {
73427567SXin.Chen@Sun.COM data <<= 8;
73437567SXin.Chen@Sun.COM data |= *p;
73447567SXin.Chen@Sun.COM }
73457567SXin.Chen@Sun.COM list_len = data;
73467567SXin.Chen@Sun.COM if (buf_len < list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE) {
73477567SXin.Chen@Sun.COM scsi_free_consistent_buf(bp);
73487567SXin.Chen@Sun.COM bp = NULL;
73497567SXin.Chen@Sun.COM buf_len = list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE;
73507567SXin.Chen@Sun.COM }
73517567SXin.Chen@Sun.COM scsi_destroy_pkt(pkt);
73527567SXin.Chen@Sun.COM }
73537567SXin.Chen@Sun.COM if (i >= 2) {
73547567SXin.Chen@Sun.COM uint8_t *buf = (uint8_t *)(bp->b_un.b_addr +
73557567SXin.Chen@Sun.COM AAC_SCSI_RPTLUNS_HEAD_SIZE);
73567567SXin.Chen@Sun.COM
73577567SXin.Chen@Sun.COM for (i = 0; i < (list_len / AAC_SCSI_RPTLUNS_ADDR_SIZE); i++) {
73587567SXin.Chen@Sun.COM uint16_t lun;
73597567SXin.Chen@Sun.COM
73607567SXin.Chen@Sun.COM /* Determine report luns addressing type */
73617567SXin.Chen@Sun.COM switch (buf[0] & AAC_SCSI_RPTLUNS_ADDR_MASK) {
73627567SXin.Chen@Sun.COM /*
73637567SXin.Chen@Sun.COM * Vendors in the field have been found to be
73647567SXin.Chen@Sun.COM * concatenating bus/target/lun to equal the
73657567SXin.Chen@Sun.COM * complete lun value instead of switching to
73667567SXin.Chen@Sun.COM * flat space addressing
73677567SXin.Chen@Sun.COM */
73687567SXin.Chen@Sun.COM case AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL:
73697567SXin.Chen@Sun.COM case AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT:
73707567SXin.Chen@Sun.COM case AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE:
73717567SXin.Chen@Sun.COM lun = ((buf[0] & 0x3f) << 8) | buf[1];
73727567SXin.Chen@Sun.COM if (lun > UINT8_MAX) {
73737567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_WARN,
73747567SXin.Chen@Sun.COM "abnormal lun number: %d", lun);
73757567SXin.Chen@Sun.COM break;
73767567SXin.Chen@Sun.COM }
73777567SXin.Chen@Sun.COM if (aac_config_lun(softs, tgt, lun, &ldip) ==
73787567SXin.Chen@Sun.COM NDI_SUCCESS)
73797567SXin.Chen@Sun.COM lun_total++;
73807567SXin.Chen@Sun.COM break;
73817567SXin.Chen@Sun.COM }
73827567SXin.Chen@Sun.COM
73837567SXin.Chen@Sun.COM buf += AAC_SCSI_RPTLUNS_ADDR_SIZE;
73847567SXin.Chen@Sun.COM }
73857567SXin.Chen@Sun.COM } else {
73867567SXin.Chen@Sun.COM /* The target may do not support SCMD_REPORT_LUNS. */
73877567SXin.Chen@Sun.COM if (aac_config_lun(softs, tgt, 0, &ldip) == NDI_SUCCESS)
73887567SXin.Chen@Sun.COM lun_total++;
73897567SXin.Chen@Sun.COM }
73907567SXin.Chen@Sun.COM scsi_free_consistent_buf(bp);
73917567SXin.Chen@Sun.COM return (lun_total);
73927567SXin.Chen@Sun.COM }
73937567SXin.Chen@Sun.COM
73947567SXin.Chen@Sun.COM static void
aac_devcfg(struct aac_softstate * softs,int tgt,int en)73957567SXin.Chen@Sun.COM aac_devcfg(struct aac_softstate *softs, int tgt, int en)
73967567SXin.Chen@Sun.COM {
73977567SXin.Chen@Sun.COM struct aac_device *dvp;
73987567SXin.Chen@Sun.COM
73997567SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
74007567SXin.Chen@Sun.COM dvp = AAC_DEV(softs, tgt);
74017567SXin.Chen@Sun.COM if (en)
74027567SXin.Chen@Sun.COM dvp->flags |= AAC_DFLAG_CONFIGURING;
74037567SXin.Chen@Sun.COM else
74047567SXin.Chen@Sun.COM dvp->flags &= ~AAC_DFLAG_CONFIGURING;
74057567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
74067567SXin.Chen@Sun.COM }
74077567SXin.Chen@Sun.COM
74087567SXin.Chen@Sun.COM static int
aac_tran_bus_config(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg,dev_info_t ** childp)74097567SXin.Chen@Sun.COM aac_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
74107567SXin.Chen@Sun.COM void *arg, dev_info_t **childp)
74117567SXin.Chen@Sun.COM {
74127567SXin.Chen@Sun.COM struct aac_softstate *softs;
74137567SXin.Chen@Sun.COM int circ = 0;
74147567SXin.Chen@Sun.COM int rval;
74157567SXin.Chen@Sun.COM
74167567SXin.Chen@Sun.COM if ((softs = ddi_get_soft_state(aac_softstatep,
74177567SXin.Chen@Sun.COM ddi_get_instance(parent))) == NULL)
74187567SXin.Chen@Sun.COM return (NDI_FAILURE);
74197567SXin.Chen@Sun.COM
74207567SXin.Chen@Sun.COM /* Commands for bus config should be blocked as the bus is quiesced */
74217567SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
74227567SXin.Chen@Sun.COM if (softs->state & AAC_STATE_QUIESCED) {
74237567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE,
74247567SXin.Chen@Sun.COM "bus_config abroted because bus is quiesced");
74257567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
74267567SXin.Chen@Sun.COM return (NDI_FAILURE);
74277567SXin.Chen@Sun.COM }
74287567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
74297567SXin.Chen@Sun.COM
74307567SXin.Chen@Sun.COM DBCALLED(softs, 1);
74317567SXin.Chen@Sun.COM
74327567SXin.Chen@Sun.COM /* Hold the nexus across the bus_config */
74337567SXin.Chen@Sun.COM ndi_devi_enter(parent, &circ);
74347567SXin.Chen@Sun.COM switch (op) {
74357567SXin.Chen@Sun.COM case BUS_CONFIG_ONE: {
74367567SXin.Chen@Sun.COM int tgt, lun;
74377567SXin.Chen@Sun.COM
74387567SXin.Chen@Sun.COM if (aac_parse_devname(arg, &tgt, &lun) != AACOK) {
74397567SXin.Chen@Sun.COM rval = NDI_FAILURE;
74407567SXin.Chen@Sun.COM break;
74417567SXin.Chen@Sun.COM }
7442*12408SZhongyan.Gu@Sun.COM if (tgt >= AAC_MAX_LD) {
7443*12408SZhongyan.Gu@Sun.COM if (tgt >= AAC_MAX_DEV(softs)) {
7444*12408SZhongyan.Gu@Sun.COM rval = NDI_FAILURE;
7445*12408SZhongyan.Gu@Sun.COM break;
7446*12408SZhongyan.Gu@Sun.COM }
7447*12408SZhongyan.Gu@Sun.COM }
74487567SXin.Chen@Sun.COM
74497567SXin.Chen@Sun.COM AAC_DEVCFG_BEGIN(softs, tgt);
74507567SXin.Chen@Sun.COM rval = aac_config_lun(softs, tgt, lun, childp);
74517567SXin.Chen@Sun.COM AAC_DEVCFG_END(softs, tgt);
74527567SXin.Chen@Sun.COM break;
74537567SXin.Chen@Sun.COM }
74547567SXin.Chen@Sun.COM
74557567SXin.Chen@Sun.COM case BUS_CONFIG_DRIVER:
74567567SXin.Chen@Sun.COM case BUS_CONFIG_ALL: {
74577567SXin.Chen@Sun.COM uint32_t bus, tgt;
74587567SXin.Chen@Sun.COM int index, total;
74597567SXin.Chen@Sun.COM
74607567SXin.Chen@Sun.COM for (tgt = 0; tgt < AAC_MAX_LD; tgt++) {
74617567SXin.Chen@Sun.COM AAC_DEVCFG_BEGIN(softs, tgt);
74627567SXin.Chen@Sun.COM (void) aac_config_lun(softs, tgt, 0, NULL);
74637567SXin.Chen@Sun.COM AAC_DEVCFG_END(softs, tgt);
74647567SXin.Chen@Sun.COM }
74657567SXin.Chen@Sun.COM
74667567SXin.Chen@Sun.COM /* Config the non-DASD devices connected to the card */
74677567SXin.Chen@Sun.COM total = 0;
74687567SXin.Chen@Sun.COM index = AAC_MAX_LD;
74697567SXin.Chen@Sun.COM for (bus = 0; bus < softs->bus_max; bus++) {
74707567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "bus %d:", bus);
74717567SXin.Chen@Sun.COM for (tgt = 0; tgt < softs->tgt_max; tgt++, index++) {
74727567SXin.Chen@Sun.COM AAC_DEVCFG_BEGIN(softs, index);
74737567SXin.Chen@Sun.COM if (aac_config_tgt(softs, index))
74747567SXin.Chen@Sun.COM total++;
74757567SXin.Chen@Sun.COM AAC_DEVCFG_END(softs, index);
74767567SXin.Chen@Sun.COM }
74777567SXin.Chen@Sun.COM }
74787567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_CONT,
74797567SXin.Chen@Sun.COM "?Total %d phys. device(s) found", total);
74807567SXin.Chen@Sun.COM rval = NDI_SUCCESS;
74817567SXin.Chen@Sun.COM break;
74827567SXin.Chen@Sun.COM }
74837567SXin.Chen@Sun.COM }
74847567SXin.Chen@Sun.COM
74857567SXin.Chen@Sun.COM if (rval == NDI_SUCCESS)
74867567SXin.Chen@Sun.COM rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
74877567SXin.Chen@Sun.COM ndi_devi_exit(parent, circ);
74887567SXin.Chen@Sun.COM return (rval);
74897567SXin.Chen@Sun.COM }
74907567SXin.Chen@Sun.COM
749111964SXin.Chen@Sun.COM /*ARGSUSED*/
749211964SXin.Chen@Sun.COM static int
aac_handle_dr(struct aac_softstate * softs,int tgt,int lun,int event)749311964SXin.Chen@Sun.COM aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
749411964SXin.Chen@Sun.COM {
74957567SXin.Chen@Sun.COM struct aac_device *dvp;
74967567SXin.Chen@Sun.COM dev_info_t *dip;
74977567SXin.Chen@Sun.COM int valid;
74987567SXin.Chen@Sun.COM int circ1 = 0;
74997567SXin.Chen@Sun.COM
75007567SXin.Chen@Sun.COM DBCALLED(softs, 1);
75017567SXin.Chen@Sun.COM
75027567SXin.Chen@Sun.COM /* Hold the nexus across the bus_config */
750311964SXin.Chen@Sun.COM dvp = AAC_DEV(softs, tgt);
75047567SXin.Chen@Sun.COM valid = AAC_DEV_IS_VALID(dvp);
75057567SXin.Chen@Sun.COM dip = dvp->dip;
750611964SXin.Chen@Sun.COM if (!(softs->state & AAC_STATE_RUN))
750711964SXin.Chen@Sun.COM return (AACERR);
75087567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
75097567SXin.Chen@Sun.COM
751011964SXin.Chen@Sun.COM switch (event) {
751111964SXin.Chen@Sun.COM case AAC_CFG_ADD:
751211964SXin.Chen@Sun.COM case AAC_CFG_DELETE:
75137567SXin.Chen@Sun.COM /* Device onlined */
75147567SXin.Chen@Sun.COM if (dip == NULL && valid) {
75157567SXin.Chen@Sun.COM ndi_devi_enter(softs->devinfo_p, &circ1);
751611964SXin.Chen@Sun.COM (void) aac_config_lun(softs, tgt, 0, NULL);
75177567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
751811964SXin.Chen@Sun.COM softs->instance, tgt, lun);
75197567SXin.Chen@Sun.COM ndi_devi_exit(softs->devinfo_p, circ1);
75207567SXin.Chen@Sun.COM }
75217567SXin.Chen@Sun.COM /* Device offlined */
75227567SXin.Chen@Sun.COM if (dip && !valid) {
75237567SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
75247567SXin.Chen@Sun.COM (void) aac_do_reset(softs);
75257567SXin.Chen@Sun.COM mutex_exit(&softs->io_lock);
75267567SXin.Chen@Sun.COM
75277567SXin.Chen@Sun.COM (void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
75287567SXin.Chen@Sun.COM AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
752911964SXin.Chen@Sun.COM softs->instance, tgt, lun);
75307567SXin.Chen@Sun.COM }
75317567SXin.Chen@Sun.COM break;
75327567SXin.Chen@Sun.COM }
753311964SXin.Chen@Sun.COM
753411964SXin.Chen@Sun.COM mutex_enter(&softs->io_lock);
75357567SXin.Chen@Sun.COM return (AACOK);
75367567SXin.Chen@Sun.COM }
75377567SXin.Chen@Sun.COM
75385678Spl196000 #ifdef DEBUG
75395678Spl196000
75405678Spl196000 /* -------------------------debug aid functions-------------------------- */
75415678Spl196000
75425678Spl196000 #define AAC_FIB_CMD_KEY_STRINGS \
75435678Spl196000 TestCommandResponse, "TestCommandResponse", \
75445678Spl196000 TestAdapterCommand, "TestAdapterCommand", \
75455678Spl196000 LastTestCommand, "LastTestCommand", \
75465678Spl196000 ReinitHostNormCommandQueue, "ReinitHostNormCommandQueue", \
75475678Spl196000 ReinitHostHighCommandQueue, "ReinitHostHighCommandQueue", \
75485678Spl196000 ReinitHostHighRespQueue, "ReinitHostHighRespQueue", \
75495678Spl196000 ReinitHostNormRespQueue, "ReinitHostNormRespQueue", \
75505678Spl196000 ReinitAdapNormCommandQueue, "ReinitAdapNormCommandQueue", \
75515678Spl196000 ReinitAdapHighCommandQueue, "ReinitAdapHighCommandQueue", \
75525678Spl196000 ReinitAdapHighRespQueue, "ReinitAdapHighRespQueue", \
75535678Spl196000 ReinitAdapNormRespQueue, "ReinitAdapNormRespQueue", \
75545678Spl196000 InterfaceShutdown, "InterfaceShutdown", \
75555678Spl196000 DmaCommandFib, "DmaCommandFib", \
75565678Spl196000 StartProfile, "StartProfile", \
75575678Spl196000 TermProfile, "TermProfile", \
75585678Spl196000 SpeedTest, "SpeedTest", \
75595678Spl196000 TakeABreakPt, "TakeABreakPt", \
75605678Spl196000 RequestPerfData, "RequestPerfData", \
75615678Spl196000 SetInterruptDefTimer, "SetInterruptDefTimer", \
75625678Spl196000 SetInterruptDefCount, "SetInterruptDefCount", \
75635678Spl196000 GetInterruptDefStatus, "GetInterruptDefStatus", \
75645678Spl196000 LastCommCommand, "LastCommCommand", \
75655678Spl196000 NuFileSystem, "NuFileSystem", \
75665678Spl196000 UFS, "UFS", \
75675678Spl196000 HostFileSystem, "HostFileSystem", \
75685678Spl196000 LastFileSystemCommand, "LastFileSystemCommand", \
75695678Spl196000 ContainerCommand, "ContainerCommand", \
75705678Spl196000 ContainerCommand64, "ContainerCommand64", \
75715678Spl196000 ClusterCommand, "ClusterCommand", \
75725678Spl196000 ScsiPortCommand, "ScsiPortCommand", \
75735678Spl196000 ScsiPortCommandU64, "ScsiPortCommandU64", \
75745678Spl196000 AifRequest, "AifRequest", \
75755678Spl196000 CheckRevision, "CheckRevision", \
75765678Spl196000 FsaHostShutdown, "FsaHostShutdown", \
75775678Spl196000 RequestAdapterInfo, "RequestAdapterInfo", \
75785678Spl196000 IsAdapterPaused, "IsAdapterPaused", \
75795678Spl196000 SendHostTime, "SendHostTime", \
75805678Spl196000 LastMiscCommand, "LastMiscCommand"
75815678Spl196000
75825678Spl196000 #define AAC_CTVM_SUBCMD_KEY_STRINGS \
75835678Spl196000 VM_Null, "VM_Null", \
75845678Spl196000 VM_NameServe, "VM_NameServe", \
75855678Spl196000 VM_ContainerConfig, "VM_ContainerConfig", \
75865678Spl196000 VM_Ioctl, "VM_Ioctl", \
75875678Spl196000 VM_FilesystemIoctl, "VM_FilesystemIoctl", \
75885678Spl196000 VM_CloseAll, "VM_CloseAll", \
75895678Spl196000 VM_CtBlockRead, "VM_CtBlockRead", \
75905678Spl196000 VM_CtBlockWrite, "VM_CtBlockWrite", \
75915678Spl196000 VM_SliceBlockRead, "VM_SliceBlockRead", \
75925678Spl196000 VM_SliceBlockWrite, "VM_SliceBlockWrite", \
75935678Spl196000 VM_DriveBlockRead, "VM_DriveBlockRead", \
75945678Spl196000 VM_DriveBlockWrite, "VM_DriveBlockWrite", \
75955678Spl196000 VM_EnclosureMgt, "VM_EnclosureMgt", \
75965678Spl196000 VM_Unused, "VM_Unused", \
75975678Spl196000 VM_CtBlockVerify, "VM_CtBlockVerify", \
75985678Spl196000 VM_CtPerf, "VM_CtPerf", \
75995678Spl196000 VM_CtBlockRead64, "VM_CtBlockRead64", \
76005678Spl196000 VM_CtBlockWrite64, "VM_CtBlockWrite64", \
76015678Spl196000 VM_CtBlockVerify64, "VM_CtBlockVerify64", \
76025678Spl196000 VM_CtHostRead64, "VM_CtHostRead64", \
76035678Spl196000 VM_CtHostWrite64, "VM_CtHostWrite64", \
76045678Spl196000 VM_NameServe64, "VM_NameServe64"
76055678Spl196000
76065678Spl196000 #define AAC_CT_SUBCMD_KEY_STRINGS \
76075678Spl196000 CT_Null, "CT_Null", \
76085678Spl196000 CT_GET_SLICE_COUNT, "CT_GET_SLICE_COUNT", \
76095678Spl196000 CT_GET_PARTITION_COUNT, "CT_GET_PARTITION_COUNT", \
76105678Spl196000 CT_GET_PARTITION_INFO, "CT_GET_PARTITION_INFO", \
76115678Spl196000 CT_GET_CONTAINER_COUNT, "CT_GET_CONTAINER_COUNT", \
76125678Spl196000 CT_GET_CONTAINER_INFO_OLD, "CT_GET_CONTAINER_INFO_OLD", \
76135678Spl196000 CT_WRITE_MBR, "CT_WRITE_MBR", \
76145678Spl196000 CT_WRITE_PARTITION, "CT_WRITE_PARTITION", \
76155678Spl196000 CT_UPDATE_PARTITION, "CT_UPDATE_PARTITION", \
76165678Spl196000 CT_UNLOAD_CONTAINER, "CT_UNLOAD_CONTAINER", \
76175678Spl196000 CT_CONFIG_SINGLE_PRIMARY, "CT_CONFIG_SINGLE_PRIMARY", \
76185678Spl196000 CT_READ_CONFIG_AGE, "CT_READ_CONFIG_AGE", \
76195678Spl196000 CT_WRITE_CONFIG_AGE, "CT_WRITE_CONFIG_AGE", \
76205678Spl196000 CT_READ_SERIAL_NUMBER, "CT_READ_SERIAL_NUMBER", \
76215678Spl196000 CT_ZERO_PAR_ENTRY, "CT_ZERO_PAR_ENTRY", \
76225678Spl196000 CT_READ_MBR, "CT_READ_MBR", \
76235678Spl196000 CT_READ_PARTITION, "CT_READ_PARTITION", \
76245678Spl196000 CT_DESTROY_CONTAINER, "CT_DESTROY_CONTAINER", \
76255678Spl196000 CT_DESTROY2_CONTAINER, "CT_DESTROY2_CONTAINER", \
76265678Spl196000 CT_SLICE_SIZE, "CT_SLICE_SIZE", \
76275678Spl196000 CT_CHECK_CONFLICTS, "CT_CHECK_CONFLICTS", \
76285678Spl196000 CT_MOVE_CONTAINER, "CT_MOVE_CONTAINER", \
76295678Spl196000 CT_READ_LAST_DRIVE, "CT_READ_LAST_DRIVE", \
76305678Spl196000 CT_WRITE_LAST_DRIVE, "CT_WRITE_LAST_DRIVE", \
76315678Spl196000 CT_UNMIRROR, "CT_UNMIRROR", \
76325678Spl196000 CT_MIRROR_DELAY, "CT_MIRROR_DELAY", \
76335678Spl196000 CT_GEN_MIRROR, "CT_GEN_MIRROR", \
76345678Spl196000 CT_GEN_MIRROR2, "CT_GEN_MIRROR2", \
76355678Spl196000 CT_TEST_CONTAINER, "CT_TEST_CONTAINER", \
76365678Spl196000 CT_MOVE2, "CT_MOVE2", \
76375678Spl196000 CT_SPLIT, "CT_SPLIT", \
76385678Spl196000 CT_SPLIT2, "CT_SPLIT2", \
76395678Spl196000 CT_SPLIT_BROKEN, "CT_SPLIT_BROKEN", \
76405678Spl196000 CT_SPLIT_BROKEN2, "CT_SPLIT_BROKEN2", \
76415678Spl196000 CT_RECONFIG, "CT_RECONFIG", \
76425678Spl196000 CT_BREAK2, "CT_BREAK2", \
76435678Spl196000 CT_BREAK, "CT_BREAK", \
76445678Spl196000 CT_MERGE2, "CT_MERGE2", \
76455678Spl196000 CT_MERGE, "CT_MERGE", \
76465678Spl196000 CT_FORCE_ERROR, "CT_FORCE_ERROR", \
76475678Spl196000 CT_CLEAR_ERROR, "CT_CLEAR_ERROR", \
76485678Spl196000 CT_ASSIGN_FAILOVER, "CT_ASSIGN_FAILOVER", \
76495678Spl196000 CT_CLEAR_FAILOVER, "CT_CLEAR_FAILOVER", \
76505678Spl196000 CT_GET_FAILOVER_DATA, "CT_GET_FAILOVER_DATA", \
76515678Spl196000 CT_VOLUME_ADD, "CT_VOLUME_ADD", \
76525678Spl196000 CT_VOLUME_ADD2, "CT_VOLUME_ADD2", \
76535678Spl196000 CT_MIRROR_STATUS, "CT_MIRROR_STATUS", \
76545678Spl196000 CT_COPY_STATUS, "CT_COPY_STATUS", \
76555678Spl196000 CT_COPY, "CT_COPY", \
76565678Spl196000 CT_UNLOCK_CONTAINER, "CT_UNLOCK_CONTAINER", \
76575678Spl196000 CT_LOCK_CONTAINER, "CT_LOCK_CONTAINER", \
76585678Spl196000 CT_MAKE_READ_ONLY, "CT_MAKE_READ_ONLY", \
76595678Spl196000 CT_MAKE_READ_WRITE, "CT_MAKE_READ_WRITE", \
76605678Spl196000 CT_CLEAN_DEAD, "CT_CLEAN_DEAD", \
76615678Spl196000 CT_ABORT_MIRROR_COMMAND, "CT_ABORT_MIRROR_COMMAND", \
76625678Spl196000 CT_SET, "CT_SET", \
76635678Spl196000 CT_GET, "CT_GET", \
76645678Spl196000 CT_GET_NVLOG_ENTRY, "CT_GET_NVLOG_ENTRY", \
76655678Spl196000 CT_GET_DELAY, "CT_GET_DELAY", \
76665678Spl196000 CT_ZERO_CONTAINER_SPACE, "CT_ZERO_CONTAINER_SPACE", \
76675678Spl196000 CT_GET_ZERO_STATUS, "CT_GET_ZERO_STATUS", \
76685678Spl196000 CT_SCRUB, "CT_SCRUB", \
76695678Spl196000 CT_GET_SCRUB_STATUS, "CT_GET_SCRUB_STATUS", \
76705678Spl196000 CT_GET_SLICE_INFO, "CT_GET_SLICE_INFO", \
76715678Spl196000 CT_GET_SCSI_METHOD, "CT_GET_SCSI_METHOD", \
76725678Spl196000 CT_PAUSE_IO, "CT_PAUSE_IO", \
76735678Spl196000 CT_RELEASE_IO, "CT_RELEASE_IO", \
76745678Spl196000 CT_SCRUB2, "CT_SCRUB2", \
76755678Spl196000 CT_MCHECK, "CT_MCHECK", \
76765678Spl196000 CT_CORRUPT, "CT_CORRUPT", \
76775678Spl196000 CT_GET_TASK_COUNT, "CT_GET_TASK_COUNT", \
76785678Spl196000 CT_PROMOTE, "CT_PROMOTE", \
76795678Spl196000 CT_SET_DEAD, "CT_SET_DEAD", \
76805678Spl196000 CT_CONTAINER_OPTIONS, "CT_CONTAINER_OPTIONS", \
76815678Spl196000 CT_GET_NV_PARAM, "CT_GET_NV_PARAM", \
76825678Spl196000 CT_GET_PARAM, "CT_GET_PARAM", \
76835678Spl196000 CT_NV_PARAM_SIZE, "CT_NV_PARAM_SIZE", \
76845678Spl196000 CT_COMMON_PARAM_SIZE, "CT_COMMON_PARAM_SIZE", \
76855678Spl196000 CT_PLATFORM_PARAM_SIZE, "CT_PLATFORM_PARAM_SIZE", \
76865678Spl196000 CT_SET_NV_PARAM, "CT_SET_NV_PARAM", \
76875678Spl196000 CT_ABORT_SCRUB, "CT_ABORT_SCRUB", \
76885678Spl196000 CT_GET_SCRUB_ERROR, "CT_GET_SCRUB_ERROR", \
76895678Spl196000 CT_LABEL_CONTAINER, "CT_LABEL_CONTAINER", \
76905678Spl196000 CT_CONTINUE_DATA, "CT_CONTINUE_DATA", \
76915678Spl196000 CT_STOP_DATA, "CT_STOP_DATA", \
76925678Spl196000 CT_GET_PARTITION_TABLE, "CT_GET_PARTITION_TABLE", \
76935678Spl196000 CT_GET_DISK_PARTITIONS, "CT_GET_DISK_PARTITIONS", \
76945678Spl196000 CT_GET_MISC_STATUS, "CT_GET_MISC_STATUS", \
76955678Spl196000 CT_GET_CONTAINER_PERF_INFO, "CT_GET_CONTAINER_PERF_INFO", \
76965678Spl196000 CT_GET_TIME, "CT_GET_TIME", \
76975678Spl196000 CT_READ_DATA, "CT_READ_DATA", \
76985678Spl196000 CT_CTR, "CT_CTR", \
76995678Spl196000 CT_CTL, "CT_CTL", \
77005678Spl196000 CT_DRAINIO, "CT_DRAINIO", \
77015678Spl196000 CT_RELEASEIO, "CT_RELEASEIO", \
77025678Spl196000 CT_GET_NVRAM, "CT_GET_NVRAM", \
77035678Spl196000 CT_GET_MEMORY, "CT_GET_MEMORY", \
77045678Spl196000 CT_PRINT_CT_LOG, "CT_PRINT_CT_LOG", \
77055678Spl196000 CT_ADD_LEVEL, "CT_ADD_LEVEL", \
77065678Spl196000 CT_NV_ZERO, "CT_NV_ZERO", \
77075678Spl196000 CT_READ_SIGNATURE, "CT_READ_SIGNATURE", \
77085678Spl196000 CT_THROTTLE_ON, "CT_THROTTLE_ON", \
77095678Spl196000 CT_THROTTLE_OFF, "CT_THROTTLE_OFF", \
77105678Spl196000 CT_GET_THROTTLE_STATS, "CT_GET_THROTTLE_STATS", \
77115678Spl196000 CT_MAKE_SNAPSHOT, "CT_MAKE_SNAPSHOT", \
77125678Spl196000 CT_REMOVE_SNAPSHOT, "CT_REMOVE_SNAPSHOT", \
77135678Spl196000 CT_WRITE_USER_FLAGS, "CT_WRITE_USER_FLAGS", \
77145678Spl196000 CT_READ_USER_FLAGS, "CT_READ_USER_FLAGS", \
77155678Spl196000 CT_MONITOR, "CT_MONITOR", \
77165678Spl196000 CT_GEN_MORPH, "CT_GEN_MORPH", \
77175678Spl196000 CT_GET_SNAPSHOT_INFO, "CT_GET_SNAPSHOT_INFO", \
77185678Spl196000 CT_CACHE_SET, "CT_CACHE_SET", \
77195678Spl196000 CT_CACHE_STAT, "CT_CACHE_STAT", \
77205678Spl196000 CT_TRACE_START, "CT_TRACE_START", \
77215678Spl196000 CT_TRACE_STOP, "CT_TRACE_STOP", \
77225678Spl196000 CT_TRACE_ENABLE, "CT_TRACE_ENABLE", \
77235678Spl196000 CT_TRACE_DISABLE, "CT_TRACE_DISABLE", \
77245678Spl196000 CT_FORCE_CORE_DUMP, "CT_FORCE_CORE_DUMP", \
77255678Spl196000 CT_SET_SERIAL_NUMBER, "CT_SET_SERIAL_NUMBER", \
77265678Spl196000 CT_RESET_SERIAL_NUMBER, "CT_RESET_SERIAL_NUMBER", \
77275678Spl196000 CT_ENABLE_RAID5, "CT_ENABLE_RAID5", \
77285678Spl196000 CT_CLEAR_VALID_DUMP_FLAG, "CT_CLEAR_VALID_DUMP_FLAG", \
77295678Spl196000 CT_GET_MEM_STATS, "CT_GET_MEM_STATS", \
77305678Spl196000 CT_GET_CORE_SIZE, "CT_GET_CORE_SIZE", \
77315678Spl196000 CT_CREATE_CONTAINER_OLD, "CT_CREATE_CONTAINER_OLD", \
77325678Spl196000 CT_STOP_DUMPS, "CT_STOP_DUMPS", \
77335678Spl196000 CT_PANIC_ON_TAKE_A_BREAK, "CT_PANIC_ON_TAKE_A_BREAK", \
77345678Spl196000 CT_GET_CACHE_STATS, "CT_GET_CACHE_STATS", \
77355678Spl196000 CT_MOVE_PARTITION, "CT_MOVE_PARTITION", \
77365678Spl196000 CT_FLUSH_CACHE, "CT_FLUSH_CACHE", \
77375678Spl196000 CT_READ_NAME, "CT_READ_NAME", \
77385678Spl196000 CT_WRITE_NAME, "CT_WRITE_NAME", \
77395678Spl196000 CT_TOSS_CACHE, "CT_TOSS_CACHE", \
77405678Spl196000 CT_LOCK_DRAINIO, "CT_LOCK_DRAINIO", \
77415678Spl196000 CT_CONTAINER_OFFLINE, "CT_CONTAINER_OFFLINE", \
77425678Spl196000 CT_SET_CACHE_SIZE, "CT_SET_CACHE_SIZE", \
77435678Spl196000 CT_CLEAN_SHUTDOWN_STATUS, "CT_CLEAN_SHUTDOWN_STATUS", \
77445678Spl196000 CT_CLEAR_DISKLOG_ON_DISK, "CT_CLEAR_DISKLOG_ON_DISK", \
77455678Spl196000 CT_CLEAR_ALL_DISKLOG, "CT_CLEAR_ALL_DISKLOG", \
77465678Spl196000 CT_CACHE_FAVOR, "CT_CACHE_FAVOR", \
77475678Spl196000 CT_READ_PASSTHRU_MBR, "CT_READ_PASSTHRU_MBR", \
77485678Spl196000 CT_SCRUB_NOFIX, "CT_SCRUB_NOFIX", \
77495678Spl196000 CT_SCRUB2_NOFIX, "CT_SCRUB2_NOFIX", \
77505678Spl196000 CT_FLUSH, "CT_FLUSH", \
77515678Spl196000 CT_REBUILD, "CT_REBUILD", \
77525678Spl196000 CT_FLUSH_CONTAINER, "CT_FLUSH_CONTAINER", \
77535678Spl196000 CT_RESTART, "CT_RESTART", \
77545678Spl196000 CT_GET_CONFIG_STATUS, "CT_GET_CONFIG_STATUS", \
77555678Spl196000 CT_TRACE_FLAG, "CT_TRACE_FLAG", \
77565678Spl196000 CT_RESTART_MORPH, "CT_RESTART_MORPH", \
77575678Spl196000 CT_GET_TRACE_INFO, "CT_GET_TRACE_INFO", \
77585678Spl196000 CT_GET_TRACE_ITEM, "CT_GET_TRACE_ITEM", \
77595678Spl196000 CT_COMMIT_CONFIG, "CT_COMMIT_CONFIG", \
77605678Spl196000 CT_CONTAINER_EXISTS, "CT_CONTAINER_EXISTS", \
77615678Spl196000 CT_GET_SLICE_FROM_DEVT, "CT_GET_SLICE_FROM_DEVT", \
77625678Spl196000 CT_OPEN_READ_WRITE, "CT_OPEN_READ_WRITE", \
77635678Spl196000 CT_WRITE_MEMORY_BLOCK, "CT_WRITE_MEMORY_BLOCK", \
77645678Spl196000 CT_GET_CACHE_PARAMS, "CT_GET_CACHE_PARAMS", \
77655678Spl196000 CT_CRAZY_CACHE, "CT_CRAZY_CACHE", \
77665678Spl196000 CT_GET_PROFILE_STRUCT, "CT_GET_PROFILE_STRUCT", \
77675678Spl196000 CT_SET_IO_TRACE_FLAG, "CT_SET_IO_TRACE_FLAG", \
77685678Spl196000 CT_GET_IO_TRACE_STRUCT, "CT_GET_IO_TRACE_STRUCT", \
77695678Spl196000 CT_CID_TO_64BITS_UID, "CT_CID_TO_64BITS_UID", \
77705678Spl196000 CT_64BITS_UID_TO_CID, "CT_64BITS_UID_TO_CID", \
77715678Spl196000 CT_PAR_TO_64BITS_UID, "CT_PAR_TO_64BITS_UID", \
77725678Spl196000 CT_CID_TO_32BITS_UID, "CT_CID_TO_32BITS_UID", \
77735678Spl196000 CT_32BITS_UID_TO_CID, "CT_32BITS_UID_TO_CID", \
77745678Spl196000 CT_PAR_TO_32BITS_UID, "CT_PAR_TO_32BITS_UID", \
77755678Spl196000 CT_SET_FAILOVER_OPTION, "CT_SET_FAILOVER_OPTION", \
77765678Spl196000 CT_GET_FAILOVER_OPTION, "CT_GET_FAILOVER_OPTION", \
77775678Spl196000 CT_STRIPE_ADD2, "CT_STRIPE_ADD2", \
77785678Spl196000 CT_CREATE_VOLUME_SET, "CT_CREATE_VOLUME_SET", \
77795678Spl196000 CT_CREATE_STRIPE_SET, "CT_CREATE_STRIPE_SET", \
77805678Spl196000 CT_VERIFY_CONTAINER, "CT_VERIFY_CONTAINER", \
77815678Spl196000 CT_IS_CONTAINER_DEAD, "CT_IS_CONTAINER_DEAD", \
77825678Spl196000 CT_GET_CONTAINER_OPTION, "CT_GET_CONTAINER_OPTION", \
77835678Spl196000 CT_GET_SNAPSHOT_UNUSED_STRUCT, "CT_GET_SNAPSHOT_UNUSED_STRUCT", \
77845678Spl196000 CT_CLEAR_SNAPSHOT_UNUSED_STRUCT, "CT_CLEAR_SNAPSHOT_UNUSED_STRUCT", \
77855678Spl196000 CT_GET_CONTAINER_INFO, "CT_GET_CONTAINER_INFO", \
77865678Spl196000 CT_CREATE_CONTAINER, "CT_CREATE_CONTAINER", \
77875678Spl196000 CT_CHANGE_CREATIONINFO, "CT_CHANGE_CREATIONINFO", \
77885678Spl196000 CT_CHECK_CONFLICT_UID, "CT_CHECK_CONFLICT_UID", \
77895678Spl196000 CT_CONTAINER_UID_CHECK, "CT_CONTAINER_UID_CHECK", \
77905678Spl196000 CT_IS_CONTAINER_MEATADATA_STANDARD, \
77915678Spl196000 "CT_IS_CONTAINER_MEATADATA_STANDARD", \
77925678Spl196000 CT_IS_SLICE_METADATA_STANDARD, "CT_IS_SLICE_METADATA_STANDARD", \
77935678Spl196000 CT_GET_IMPORT_COUNT, "CT_GET_IMPORT_COUNT", \
77945678Spl196000 CT_CANCEL_ALL_IMPORTS, "CT_CANCEL_ALL_IMPORTS", \
77955678Spl196000 CT_GET_IMPORT_INFO, "CT_GET_IMPORT_INFO", \
77965678Spl196000 CT_IMPORT_ARRAY, "CT_IMPORT_ARRAY", \
77975678Spl196000 CT_GET_LOG_SIZE, "CT_GET_LOG_SIZE", \
77985678Spl196000 CT_ALARM_GET_STATE, "CT_ALARM_GET_STATE", \
77995678Spl196000 CT_ALARM_SET_STATE, "CT_ALARM_SET_STATE", \
78005678Spl196000 CT_ALARM_ON_OFF, "CT_ALARM_ON_OFF", \
78015678Spl196000 CT_GET_EE_OEM_ID, "CT_GET_EE_OEM_ID", \
78025678Spl196000 CT_GET_PPI_HEADERS, "CT_GET_PPI_HEADERS", \
78035678Spl196000 CT_GET_PPI_DATA, "CT_GET_PPI_DATA", \
78045678Spl196000 CT_GET_PPI_ENTRIES, "CT_GET_PPI_ENTRIES", \
78055678Spl196000 CT_DELETE_PPI_BUNDLE, "CT_DELETE_PPI_BUNDLE", \
78065678Spl196000 CT_GET_PARTITION_TABLE_2, "CT_GET_PARTITION_TABLE_2", \
78075678Spl196000 CT_GET_PARTITION_INFO_2, "CT_GET_PARTITION_INFO_2", \
78085678Spl196000 CT_GET_DISK_PARTITIONS_2, "CT_GET_DISK_PARTITIONS_2", \
78095678Spl196000 CT_QUIESCE_ADAPTER, "CT_QUIESCE_ADAPTER", \
78105678Spl196000 CT_CLEAR_PPI_TABLE, "CT_CLEAR_PPI_TABLE"
78115678Spl196000
78125678Spl196000 #define AAC_CL_SUBCMD_KEY_STRINGS \
78135678Spl196000 CL_NULL, "CL_NULL", \
78145678Spl196000 DS_INIT, "DS_INIT", \
78155678Spl196000 DS_RESCAN, "DS_RESCAN", \
78165678Spl196000 DS_CREATE, "DS_CREATE", \
78175678Spl196000 DS_DELETE, "DS_DELETE", \
78185678Spl196000 DS_ADD_DISK, "DS_ADD_DISK", \
78195678Spl196000 DS_REMOVE_DISK, "DS_REMOVE_DISK", \
78205678Spl196000 DS_MOVE_DISK, "DS_MOVE_DISK", \
78215678Spl196000 DS_TAKE_OWNERSHIP, "DS_TAKE_OWNERSHIP", \
78225678Spl196000 DS_RELEASE_OWNERSHIP, "DS_RELEASE_OWNERSHIP", \
78235678Spl196000 DS_FORCE_OWNERSHIP, "DS_FORCE_OWNERSHIP", \
78245678Spl196000 DS_GET_DISK_SET_PARAM, "DS_GET_DISK_SET_PARAM", \
78255678Spl196000 DS_GET_DRIVE_PARAM, "DS_GET_DRIVE_PARAM", \
78265678Spl196000 DS_GET_SLICE_PARAM, "DS_GET_SLICE_PARAM", \
78275678Spl196000 DS_GET_DISK_SETS, "DS_GET_DISK_SETS", \
78285678Spl196000 DS_GET_DRIVES, "DS_GET_DRIVES", \
78295678Spl196000 DS_SET_DISK_SET_PARAM, "DS_SET_DISK_SET_PARAM", \
78305678Spl196000 DS_ONLINE, "DS_ONLINE", \
78315678Spl196000 DS_OFFLINE, "DS_OFFLINE", \
78325678Spl196000 DS_ONLINE_CONTAINERS, "DS_ONLINE_CONTAINERS", \
78335678Spl196000 DS_FSAPRINT, "DS_FSAPRINT", \
78345678Spl196000 CL_CFG_SET_HOST_IDS, "CL_CFG_SET_HOST_IDS", \
78355678Spl196000 CL_CFG_SET_PARTNER_HOST_IDS, "CL_CFG_SET_PARTNER_HOST_IDS", \
78365678Spl196000 CL_CFG_GET_CLUSTER_CONFIG, "CL_CFG_GET_CLUSTER_CONFIG", \
78375678Spl196000 CC_CLI_CLEAR_MESSAGE_BUFFER, "CC_CLI_CLEAR_MESSAGE_BUFFER", \
78385678Spl196000 CC_SRV_CLEAR_MESSAGE_BUFFER, "CC_SRV_CLEAR_MESSAGE_BUFFER", \
78395678Spl196000 CC_CLI_SHOW_MESSAGE_BUFFER, "CC_CLI_SHOW_MESSAGE_BUFFER", \
78405678Spl196000 CC_SRV_SHOW_MESSAGE_BUFFER, "CC_SRV_SHOW_MESSAGE_BUFFER", \
78415678Spl196000 CC_CLI_SEND_MESSAGE, "CC_CLI_SEND_MESSAGE", \
78425678Spl196000 CC_SRV_SEND_MESSAGE, "CC_SRV_SEND_MESSAGE", \
78435678Spl196000 CC_CLI_GET_MESSAGE, "CC_CLI_GET_MESSAGE", \
78445678Spl196000 CC_SRV_GET_MESSAGE, "CC_SRV_GET_MESSAGE", \
78455678Spl196000 CC_SEND_TEST_MESSAGE, "CC_SEND_TEST_MESSAGE", \
78465678Spl196000 CC_GET_BUSINFO, "CC_GET_BUSINFO", \
78475678Spl196000 CC_GET_PORTINFO, "CC_GET_PORTINFO", \
78485678Spl196000 CC_GET_NAMEINFO, "CC_GET_NAMEINFO", \
78495678Spl196000 CC_GET_CONFIGINFO, "CC_GET_CONFIGINFO", \
78505678Spl196000 CQ_QUORUM_OP, "CQ_QUORUM_OP"
78515678Spl196000
78525678Spl196000 #define AAC_AIF_SUBCMD_KEY_STRINGS \
78535678Spl196000 AifCmdEventNotify, "AifCmdEventNotify", \
78545678Spl196000 AifCmdJobProgress, "AifCmdJobProgress", \
78555678Spl196000 AifCmdAPIReport, "AifCmdAPIReport", \
78565678Spl196000 AifCmdDriverNotify, "AifCmdDriverNotify", \
78575678Spl196000 AifReqJobList, "AifReqJobList", \
78585678Spl196000 AifReqJobsForCtr, "AifReqJobsForCtr", \
78595678Spl196000 AifReqJobsForScsi, "AifReqJobsForScsi", \
78605678Spl196000 AifReqJobReport, "AifReqJobReport", \
78615678Spl196000 AifReqTerminateJob, "AifReqTerminateJob", \
78625678Spl196000 AifReqSuspendJob, "AifReqSuspendJob", \
78635678Spl196000 AifReqResumeJob, "AifReqResumeJob", \
78645678Spl196000 AifReqSendAPIReport, "AifReqSendAPIReport", \
78655678Spl196000 AifReqAPIJobStart, "AifReqAPIJobStart", \
78665678Spl196000 AifReqAPIJobUpdate, "AifReqAPIJobUpdate", \
78675678Spl196000 AifReqAPIJobFinish, "AifReqAPIJobFinish"
78685678Spl196000
78695678Spl196000 #define AAC_IOCTL_SUBCMD_KEY_STRINGS \
78705678Spl196000 Reserved_IOCTL, "Reserved_IOCTL", \
78715678Spl196000 GetDeviceHandle, "GetDeviceHandle", \
78725678Spl196000 BusTargetLun_to_DeviceHandle, "BusTargetLun_to_DeviceHandle", \
78735678Spl196000 DeviceHandle_to_BusTargetLun, "DeviceHandle_to_BusTargetLun", \
78745678Spl196000 RescanBus, "RescanBus", \
78755678Spl196000 GetDeviceProbeInfo, "GetDeviceProbeInfo", \
78765678Spl196000 GetDeviceCapacity, "GetDeviceCapacity", \
78775678Spl196000 GetContainerProbeInfo, "GetContainerProbeInfo", \
78785678Spl196000 GetRequestedMemorySize, "GetRequestedMemorySize", \
78795678Spl196000 GetBusInfo, "GetBusInfo", \
78805678Spl196000 GetVendorSpecific, "GetVendorSpecific", \
78815678Spl196000 EnhancedGetDeviceProbeInfo, "EnhancedGetDeviceProbeInfo", \
78825678Spl196000 EnhancedGetBusInfo, "EnhancedGetBusInfo", \
78835678Spl196000 SetupExtendedCounters, "SetupExtendedCounters", \
78845678Spl196000 GetPerformanceCounters, "GetPerformanceCounters", \
78855678Spl196000 ResetPerformanceCounters, "ResetPerformanceCounters", \
78865678Spl196000 ReadModePage, "ReadModePage", \
78875678Spl196000 WriteModePage, "WriteModePage", \
78885678Spl196000 ReadDriveParameter, "ReadDriveParameter", \
78895678Spl196000 WriteDriveParameter, "WriteDriveParameter", \
78905678Spl196000 ResetAdapter, "ResetAdapter", \
78915678Spl196000 ResetBus, "ResetBus", \
78925678Spl196000 ResetBusDevice, "ResetBusDevice", \
78935678Spl196000 ExecuteSrb, "ExecuteSrb", \
78945678Spl196000 Create_IO_Task, "Create_IO_Task", \
78955678Spl196000 Delete_IO_Task, "Delete_IO_Task", \
78965678Spl196000 Get_IO_Task_Info, "Get_IO_Task_Info", \
78975678Spl196000 Check_Task_Progress, "Check_Task_Progress", \
78985678Spl196000 InjectError, "InjectError", \
78995678Spl196000 GetDeviceDefectCounts, "GetDeviceDefectCounts", \
79005678Spl196000 GetDeviceDefectInfo, "GetDeviceDefectInfo", \
79015678Spl196000 GetDeviceStatus, "GetDeviceStatus", \
79025678Spl196000 ClearDeviceStatus, "ClearDeviceStatus", \
79035678Spl196000 DiskSpinControl, "DiskSpinControl", \
79045678Spl196000 DiskSmartControl, "DiskSmartControl", \
79055678Spl196000 WriteSame, "WriteSame", \
79065678Spl196000 ReadWriteLong, "ReadWriteLong", \
79075678Spl196000 FormatUnit, "FormatUnit", \
79085678Spl196000 TargetDeviceControl, "TargetDeviceControl", \
79095678Spl196000 TargetChannelControl, "TargetChannelControl", \
79105678Spl196000 FlashNewCode, "FlashNewCode", \
79115678Spl196000 DiskCheck, "DiskCheck", \
79125678Spl196000 RequestSense, "RequestSense", \
79135678Spl196000 DiskPERControl, "DiskPERControl", \
79145678Spl196000 Read10, "Read10", \
79155678Spl196000 Write10, "Write10"
79165678Spl196000
79175678Spl196000 #define AAC_AIFEN_KEY_STRINGS \
79185678Spl196000 AifEnGeneric, "Generic", \
79195678Spl196000 AifEnTaskComplete, "TaskComplete", \
79205678Spl196000 AifEnConfigChange, "Config change", \
79215678Spl196000 AifEnContainerChange, "Container change", \
79225678Spl196000 AifEnDeviceFailure, "device failed", \
79235678Spl196000 AifEnMirrorFailover, "Mirror failover", \
79245678Spl196000 AifEnContainerEvent, "container event", \
79255678Spl196000 AifEnFileSystemChange, "File system changed", \
79265678Spl196000 AifEnConfigPause, "Container pause event", \
79275678Spl196000 AifEnConfigResume, "Container resume event", \
79285678Spl196000 AifEnFailoverChange, "Failover space assignment changed", \
79295678Spl196000 AifEnRAID5RebuildDone, "RAID5 rebuild finished", \
79305678Spl196000 AifEnEnclosureManagement, "Enclosure management event", \
79315678Spl196000 AifEnBatteryEvent, "battery event", \
79325678Spl196000 AifEnAddContainer, "Add container", \
79335678Spl196000 AifEnDeleteContainer, "Delete container", \
79345678Spl196000 AifEnSMARTEvent, "SMART Event", \
79355678Spl196000 AifEnBatteryNeedsRecond, "battery needs reconditioning", \
79365678Spl196000 AifEnClusterEvent, "cluster event", \
79375678Spl196000 AifEnDiskSetEvent, "disk set event occured", \
79385678Spl196000 AifDenMorphComplete, "morph operation completed", \
79395678Spl196000 AifDenVolumeExtendComplete, "VolumeExtendComplete"
79405678Spl196000
79415678Spl196000 struct aac_key_strings {
79425678Spl196000 int key;
79435678Spl196000 char *message;
79445678Spl196000 };
79455678Spl196000
79465678Spl196000 extern struct scsi_key_strings scsi_cmds[];
79475678Spl196000
79485678Spl196000 static struct aac_key_strings aac_fib_cmds[] = {
79495678Spl196000 AAC_FIB_CMD_KEY_STRINGS,
79505678Spl196000 -1, NULL
79515678Spl196000 };
79525678Spl196000
79535678Spl196000 static struct aac_key_strings aac_ctvm_subcmds[] = {
79545678Spl196000 AAC_CTVM_SUBCMD_KEY_STRINGS,
79555678Spl196000 -1, NULL
79565678Spl196000 };
79575678Spl196000
79585678Spl196000 static struct aac_key_strings aac_ct_subcmds[] = {
79595678Spl196000 AAC_CT_SUBCMD_KEY_STRINGS,
79605678Spl196000 -1, NULL
79615678Spl196000 };
79625678Spl196000
79635678Spl196000 static struct aac_key_strings aac_cl_subcmds[] = {
79645678Spl196000 AAC_CL_SUBCMD_KEY_STRINGS,
79655678Spl196000 -1, NULL
79665678Spl196000 };
79675678Spl196000
79685678Spl196000 static struct aac_key_strings aac_aif_subcmds[] = {
79695678Spl196000 AAC_AIF_SUBCMD_KEY_STRINGS,
79705678Spl196000 -1, NULL
79715678Spl196000 };
79725678Spl196000
79735678Spl196000 static struct aac_key_strings aac_ioctl_subcmds[] = {
79745678Spl196000 AAC_IOCTL_SUBCMD_KEY_STRINGS,
79755678Spl196000 -1, NULL
79765678Spl196000 };
79775678Spl196000
79785678Spl196000 static struct aac_key_strings aac_aifens[] = {
79795678Spl196000 AAC_AIFEN_KEY_STRINGS,
79805678Spl196000 -1, NULL
79815678Spl196000 };
79825678Spl196000
79835678Spl196000 /*
79845678Spl196000 * The following function comes from Adaptec:
79855678Spl196000 *
79865678Spl196000 * Get the firmware print buffer parameters from the firmware,
79875678Spl196000 * if the command was successful map in the address.
79885678Spl196000 */
79895678Spl196000 static int
aac_get_fw_debug_buffer(struct aac_softstate * softs)79905678Spl196000 aac_get_fw_debug_buffer(struct aac_softstate *softs)
79915678Spl196000 {
79925678Spl196000 if (aac_sync_mbcommand(softs, AAC_MONKER_GETDRVPROP,
79935678Spl196000 0, 0, 0, 0, NULL) == AACOK) {
79945678Spl196000 uint32_t mondrv_buf_paddrl = AAC_MAILBOX_GET(softs, 1);
79955678Spl196000 uint32_t mondrv_buf_paddrh = AAC_MAILBOX_GET(softs, 2);
79965678Spl196000 uint32_t mondrv_buf_size = AAC_MAILBOX_GET(softs, 3);
79975678Spl196000 uint32_t mondrv_hdr_size = AAC_MAILBOX_GET(softs, 4);
79985678Spl196000
79995678Spl196000 if (mondrv_buf_size) {
80005678Spl196000 uint32_t offset = mondrv_buf_paddrl - \
80015678Spl196000 softs->pci_mem_base_paddr;
80025678Spl196000
80035678Spl196000 /*
80045678Spl196000 * See if the address is already mapped in, and
80055678Spl196000 * if so set it up from the base address
80065678Spl196000 */
80075678Spl196000 if ((mondrv_buf_paddrh == 0) &&
80085678Spl196000 (offset + mondrv_buf_size < softs->map_size)) {
80095678Spl196000 mutex_enter(&aac_prt_mutex);
80105678Spl196000 softs->debug_buf_offset = offset;
80115678Spl196000 softs->debug_header_size = mondrv_hdr_size;
80125678Spl196000 softs->debug_buf_size = mondrv_buf_size;
80135678Spl196000 softs->debug_fw_flags = 0;
80145678Spl196000 softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
80155678Spl196000 mutex_exit(&aac_prt_mutex);
80165678Spl196000
80175678Spl196000 return (AACOK);
80185678Spl196000 }
80195678Spl196000 }
80205678Spl196000 }
80215678Spl196000 return (AACERR);
80225678Spl196000 }
80235678Spl196000
80245678Spl196000 int
aac_dbflag_on(struct aac_softstate * softs,int flag)80255678Spl196000 aac_dbflag_on(struct aac_softstate *softs, int flag)
80265678Spl196000 {
80275678Spl196000 int debug_flags = softs ? softs->debug_flags : aac_debug_flags;
80285678Spl196000
80295678Spl196000 return ((debug_flags & (AACDB_FLAGS_FW_PRINT | \
80305678Spl196000 AACDB_FLAGS_KERNEL_PRINT)) && (debug_flags & flag));
80315678Spl196000 }
80325678Spl196000
80335678Spl196000 static void
aac_cmn_err(struct aac_softstate * softs,uint_t lev,char sl,int noheader)80345678Spl196000 aac_cmn_err(struct aac_softstate *softs, uint_t lev, char sl, int noheader)
80355678Spl196000 {
80365678Spl196000 if (noheader) {
80375678Spl196000 if (sl) {
80385678Spl196000 aac_fmt[0] = sl;
80395678Spl196000 cmn_err(lev, aac_fmt, aac_prt_buf);
80405678Spl196000 } else {
80415678Spl196000 cmn_err(lev, &aac_fmt[1], aac_prt_buf);
80425678Spl196000 }
80435678Spl196000 } else {
80445678Spl196000 if (sl) {
80455678Spl196000 aac_fmt_header[0] = sl;
80465678Spl196000 cmn_err(lev, aac_fmt_header,
80475678Spl196000 softs->vendor_name, softs->instance,
80485678Spl196000 aac_prt_buf);
80495678Spl196000 } else {
80505678Spl196000 cmn_err(lev, &aac_fmt_header[1],
80515678Spl196000 softs->vendor_name, softs->instance,
80525678Spl196000 aac_prt_buf);
80535678Spl196000 }
80545678Spl196000 }
80555678Spl196000 }
80565678Spl196000
80575678Spl196000 /*
80585678Spl196000 * The following function comes from Adaptec:
80595678Spl196000 *
80605678Spl196000 * Format and print out the data passed in to UART or console
80615678Spl196000 * as specified by debug flags.
80625678Spl196000 */
80635678Spl196000 void
aac_printf(struct aac_softstate * softs,uint_t lev,const char * fmt,...)80645678Spl196000 aac_printf(struct aac_softstate *softs, uint_t lev, const char *fmt, ...)
80655678Spl196000 {
80665678Spl196000 va_list args;
80675678Spl196000 char sl; /* system log character */
80685678Spl196000
80695678Spl196000 mutex_enter(&aac_prt_mutex);
80705678Spl196000 /* Set up parameters and call sprintf function to format the data */
80715678Spl196000 if (strchr("^!?", fmt[0]) == NULL) {
80725678Spl196000 sl = 0;
80735678Spl196000 } else {
80745678Spl196000 sl = fmt[0];
80755678Spl196000 fmt++;
80765678Spl196000 }
80775678Spl196000 va_start(args, fmt);
80785678Spl196000 (void) vsprintf(aac_prt_buf, fmt, args);
80795678Spl196000 va_end(args);
80805678Spl196000
80815678Spl196000 /* Make sure the softs structure has been passed in for this section */
80825678Spl196000 if (softs) {
80835678Spl196000 if ((softs->debug_flags & AACDB_FLAGS_FW_PRINT) &&
80845678Spl196000 /* If we are set up for a Firmware print */
80855678Spl196000 (softs->debug_buf_size)) {
80865678Spl196000 uint32_t count, i;
80875678Spl196000
80885678Spl196000 /* Make sure the string size is within boundaries */
80895678Spl196000 count = strlen(aac_prt_buf);
80905678Spl196000 if (count > softs->debug_buf_size)
80915678Spl196000 count = (uint16_t)softs->debug_buf_size;
80925678Spl196000
80935678Spl196000 /*
80945678Spl196000 * Wait for no more than AAC_PRINT_TIMEOUT for the
80955678Spl196000 * previous message length to clear (the handshake).
80965678Spl196000 */
80975678Spl196000 for (i = 0; i < AAC_PRINT_TIMEOUT; i++) {
80985678Spl196000 if (!PCI_MEM_GET32(softs,
80995678Spl196000 softs->debug_buf_offset + \
81005678Spl196000 AAC_FW_DBG_STRLEN_OFFSET))
81015678Spl196000 break;
81025678Spl196000
81035678Spl196000 drv_usecwait(1000);
81045678Spl196000 }
81055678Spl196000
81065678Spl196000 /*
81075678Spl196000 * If the length is clear, copy over the message, the
81085678Spl196000 * flags, and the length. Make sure the length is the
81095678Spl196000 * last because that is the signal for the Firmware to
81105678Spl196000 * pick it up.
81115678Spl196000 */
81125678Spl196000 if (!PCI_MEM_GET32(softs, softs->debug_buf_offset + \
81135678Spl196000 AAC_FW_DBG_STRLEN_OFFSET)) {
81145678Spl196000 PCI_MEM_REP_PUT8(softs,
81155678Spl196000 softs->debug_buf_offset + \
81165678Spl196000 softs->debug_header_size,
81175678Spl196000 aac_prt_buf, count);
81185678Spl196000 PCI_MEM_PUT32(softs,
81195678Spl196000 softs->debug_buf_offset + \
81205678Spl196000 AAC_FW_DBG_FLAGS_OFFSET,
81215678Spl196000 softs->debug_fw_flags);
81225678Spl196000 PCI_MEM_PUT32(softs,
81235678Spl196000 softs->debug_buf_offset + \
81245678Spl196000 AAC_FW_DBG_STRLEN_OFFSET, count);
81255678Spl196000 } else {
81265678Spl196000 cmn_err(CE_WARN, "UART output fail");
81275678Spl196000 softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
81285678Spl196000 }
81295678Spl196000 }
81305678Spl196000
81315678Spl196000 /*
81325678Spl196000 * If the Kernel Debug Print flag is set, send it off
81335678Spl196000 * to the Kernel Debugger
81345678Spl196000 */
81355678Spl196000 if (softs->debug_flags & AACDB_FLAGS_KERNEL_PRINT)
81365678Spl196000 aac_cmn_err(softs, lev, sl,
81375678Spl196000 (softs->debug_flags & AACDB_FLAGS_NO_HEADERS));
81385678Spl196000 } else {
81395678Spl196000 /* Driver not initialized yet, no firmware or header output */
81405678Spl196000 if (aac_debug_flags & AACDB_FLAGS_KERNEL_PRINT)
81415678Spl196000 aac_cmn_err(softs, lev, sl, 1);
81425678Spl196000 }
81435678Spl196000 mutex_exit(&aac_prt_mutex);
81445678Spl196000 }
81455678Spl196000
81465678Spl196000 /*
81475678Spl196000 * Translate command number to description string
81485678Spl196000 */
81495678Spl196000 static char *
aac_cmd_name(int cmd,struct aac_key_strings * cmdlist)81505678Spl196000 aac_cmd_name(int cmd, struct aac_key_strings *cmdlist)
81515678Spl196000 {
81525678Spl196000 int i;
81535678Spl196000
81545678Spl196000 for (i = 0; cmdlist[i].key != -1; i++) {
81555678Spl196000 if (cmd == cmdlist[i].key)
81565678Spl196000 return (cmdlist[i].message);
81575678Spl196000 }
81585678Spl196000 return (NULL);
81595678Spl196000 }
81605678Spl196000
81615678Spl196000 static void
aac_print_scmd(struct aac_softstate * softs,struct aac_cmd * acp)81625678Spl196000 aac_print_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
81635678Spl196000 {
81645678Spl196000 struct scsi_pkt *pkt = acp->pkt;
81655678Spl196000 struct scsi_address *ap = &pkt->pkt_address;
81667567SXin.Chen@Sun.COM int is_pd = 0;
81675678Spl196000 int ctl = ddi_get_instance(softs->devinfo_p);
81685678Spl196000 int tgt = ap->a_target;
81695678Spl196000 int lun = ap->a_lun;
81707100Spl196000 union scsi_cdb *cdbp = (void *)pkt->pkt_cdbp;
81715678Spl196000 uchar_t cmd = cdbp->scc_cmd;
81725678Spl196000 char *desc;
81735678Spl196000
81747567SXin.Chen@Sun.COM if (tgt >= AAC_MAX_LD) {
81757567SXin.Chen@Sun.COM is_pd = 1;
81767567SXin.Chen@Sun.COM ctl = ((struct aac_nondasd *)acp->dvp)->bus;
81777567SXin.Chen@Sun.COM tgt = ((struct aac_nondasd *)acp->dvp)->tid;
81787567SXin.Chen@Sun.COM lun = 0;
81797567SXin.Chen@Sun.COM }
81807567SXin.Chen@Sun.COM
81815678Spl196000 if ((desc = aac_cmd_name(cmd,
81825678Spl196000 (struct aac_key_strings *)scsi_cmds)) == NULL) {
81835678Spl196000 aac_printf(softs, CE_NOTE,
81847567SXin.Chen@Sun.COM "SCMD> Unknown(0x%2x) --> c%dt%dL%d %s",
81857567SXin.Chen@Sun.COM cmd, ctl, tgt, lun, is_pd ? "(pd)" : "");
81865678Spl196000 return;
81875678Spl196000 }
81885678Spl196000
81895678Spl196000 switch (cmd) {
81905678Spl196000 case SCMD_READ:
81915678Spl196000 case SCMD_WRITE:
81925678Spl196000 aac_printf(softs, CE_NOTE,
81937567SXin.Chen@Sun.COM "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
81945678Spl196000 desc, GETG0ADDR(cdbp), GETG0COUNT(cdbp),
81955678Spl196000 (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
81967567SXin.Chen@Sun.COM ctl, tgt, lun, is_pd ? "(pd)" : "");
81975678Spl196000 break;
81985678Spl196000 case SCMD_READ_G1:
81995678Spl196000 case SCMD_WRITE_G1:
82005678Spl196000 aac_printf(softs, CE_NOTE,
82017567SXin.Chen@Sun.COM "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
82025678Spl196000 desc, GETG1ADDR(cdbp), GETG1COUNT(cdbp),
82035678Spl196000 (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
82047567SXin.Chen@Sun.COM ctl, tgt, lun, is_pd ? "(pd)" : "");
82055678Spl196000 break;
82065678Spl196000 case SCMD_READ_G4:
82075678Spl196000 case SCMD_WRITE_G4:
82085678Spl196000 aac_printf(softs, CE_NOTE,
82097567SXin.Chen@Sun.COM "SCMD> %s 0x%x.%08x[%d] %s --> c%dt%dL%d %s",
82105678Spl196000 desc, GETG4ADDR(cdbp), GETG4ADDRTL(cdbp),
82115678Spl196000 GETG4COUNT(cdbp),
82125678Spl196000 (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
82137567SXin.Chen@Sun.COM ctl, tgt, lun, is_pd ? "(pd)" : "");
82147567SXin.Chen@Sun.COM break;
82157567SXin.Chen@Sun.COM case SCMD_READ_G5:
82167567SXin.Chen@Sun.COM case SCMD_WRITE_G5:
82177567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE,
82187567SXin.Chen@Sun.COM "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
82197567SXin.Chen@Sun.COM desc, GETG5ADDR(cdbp), GETG5COUNT(cdbp),
82207567SXin.Chen@Sun.COM (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
82217567SXin.Chen@Sun.COM ctl, tgt, lun, is_pd ? "(pd)" : "");
82225678Spl196000 break;
82235678Spl196000 default:
82247567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, "SCMD> %s --> c%dt%dL%d %s",
82257567SXin.Chen@Sun.COM desc, ctl, tgt, lun, is_pd ? "(pd)" : "");
82265678Spl196000 }
82275678Spl196000 }
82285678Spl196000
82295678Spl196000 void
aac_print_fib(struct aac_softstate * softs,struct aac_slot * slotp)82307567SXin.Chen@Sun.COM aac_print_fib(struct aac_softstate *softs, struct aac_slot *slotp)
82317567SXin.Chen@Sun.COM {
82327567SXin.Chen@Sun.COM struct aac_cmd *acp = slotp->acp;
82337567SXin.Chen@Sun.COM struct aac_fib *fibp = slotp->fibp;
82347567SXin.Chen@Sun.COM ddi_acc_handle_t acc = slotp->fib_acc_handle;
82355678Spl196000 uint16_t fib_size;
82367567SXin.Chen@Sun.COM uint32_t fib_cmd, sub_cmd;
82375678Spl196000 char *cmdstr, *subcmdstr;
82387567SXin.Chen@Sun.COM char *caller;
82397567SXin.Chen@Sun.COM int i;
82407567SXin.Chen@Sun.COM
82417567SXin.Chen@Sun.COM if (acp) {
82427567SXin.Chen@Sun.COM if (!(softs->debug_fib_flags & acp->fib_flags))
82437567SXin.Chen@Sun.COM return;
82447567SXin.Chen@Sun.COM if (acp->fib_flags & AACDB_FLAGS_FIB_SCMD)
82457567SXin.Chen@Sun.COM caller = "SCMD";
82467567SXin.Chen@Sun.COM else if (acp->fib_flags & AACDB_FLAGS_FIB_IOCTL)
82477567SXin.Chen@Sun.COM caller = "IOCTL";
82487567SXin.Chen@Sun.COM else if (acp->fib_flags & AACDB_FLAGS_FIB_SRB)
82497567SXin.Chen@Sun.COM caller = "SRB";
82507567SXin.Chen@Sun.COM else
82517567SXin.Chen@Sun.COM return;
82527567SXin.Chen@Sun.COM } else {
82537567SXin.Chen@Sun.COM if (!(softs->debug_fib_flags & AACDB_FLAGS_FIB_SYNC))
82547567SXin.Chen@Sun.COM return;
82557567SXin.Chen@Sun.COM caller = "SYNC";
82567567SXin.Chen@Sun.COM }
82577567SXin.Chen@Sun.COM
82587567SXin.Chen@Sun.COM fib_cmd = ddi_get16(acc, &fibp->Header.Command);
82595678Spl196000 cmdstr = aac_cmd_name(fib_cmd, aac_fib_cmds);
82607567SXin.Chen@Sun.COM sub_cmd = (uint32_t)-1;
82615678Spl196000 subcmdstr = NULL;
82625678Spl196000
82637567SXin.Chen@Sun.COM /* Print FIB header */
82647567SXin.Chen@Sun.COM if (softs->debug_fib_flags & AACDB_FLAGS_FIB_HEADER) {
82657567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, "FIB> from %s", caller);
82667567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " XferState %d",
82677567SXin.Chen@Sun.COM ddi_get32(acc, &fibp->Header.XferState));
82687567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " Command %d",
82697567SXin.Chen@Sun.COM ddi_get16(acc, &fibp->Header.Command));
82707567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " StructType %d",
82717567SXin.Chen@Sun.COM ddi_get8(acc, &fibp->Header.StructType));
82727567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " Flags 0x%x",
82737567SXin.Chen@Sun.COM ddi_get8(acc, &fibp->Header.Flags));
82747567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " Size %d",
82757567SXin.Chen@Sun.COM ddi_get16(acc, &fibp->Header.Size));
82767567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " SenderSize %d",
82777567SXin.Chen@Sun.COM ddi_get16(acc, &fibp->Header.SenderSize));
82787567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " SenderAddr 0x%x",
82797567SXin.Chen@Sun.COM ddi_get32(acc, &fibp->Header.SenderFibAddress));
82807567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " RcvrAddr 0x%x",
82817567SXin.Chen@Sun.COM ddi_get32(acc, &fibp->Header.ReceiverFibAddress));
82827567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " SenderData 0x%x",
82837567SXin.Chen@Sun.COM ddi_get32(acc, &fibp->Header.SenderData));
82847567SXin.Chen@Sun.COM }
82857567SXin.Chen@Sun.COM
82867567SXin.Chen@Sun.COM /* Print FIB data */
82875678Spl196000 switch (fib_cmd) {
82885678Spl196000 case ContainerCommand:
82897567SXin.Chen@Sun.COM sub_cmd = ddi_get32(acc,
82907567SXin.Chen@Sun.COM (void *)&(((uint32_t *)(void *)&fibp->data[0])[0]));
82915678Spl196000 subcmdstr = aac_cmd_name(sub_cmd, aac_ctvm_subcmds);
82925678Spl196000 if (subcmdstr == NULL)
82935678Spl196000 break;
82947567SXin.Chen@Sun.COM
82957567SXin.Chen@Sun.COM switch (sub_cmd) {
82967567SXin.Chen@Sun.COM case VM_ContainerConfig: {
82977567SXin.Chen@Sun.COM struct aac_Container *pContainer =
82987567SXin.Chen@Sun.COM (struct aac_Container *)fibp->data;
82997567SXin.Chen@Sun.COM
83007567SXin.Chen@Sun.COM fib_cmd = sub_cmd;
83017567SXin.Chen@Sun.COM cmdstr = subcmdstr;
83027567SXin.Chen@Sun.COM sub_cmd = (uint32_t)-1;
83037567SXin.Chen@Sun.COM subcmdstr = NULL;
83047567SXin.Chen@Sun.COM
83057567SXin.Chen@Sun.COM sub_cmd = ddi_get32(acc,
83067567SXin.Chen@Sun.COM &pContainer->CTCommand.command);
83075678Spl196000 subcmdstr = aac_cmd_name(sub_cmd, aac_ct_subcmds);
83085678Spl196000 if (subcmdstr == NULL)
83095678Spl196000 break;
83105678Spl196000 aac_printf(softs, CE_NOTE, "FIB> %s (0x%x, 0x%x, 0x%x)",
83115678Spl196000 subcmdstr,
83127567SXin.Chen@Sun.COM ddi_get32(acc, &pContainer->CTCommand.param[0]),
83137567SXin.Chen@Sun.COM ddi_get32(acc, &pContainer->CTCommand.param[1]),
83147567SXin.Chen@Sun.COM ddi_get32(acc, &pContainer->CTCommand.param[2]));
83155678Spl196000 return;
83167567SXin.Chen@Sun.COM }
83177567SXin.Chen@Sun.COM
83185678Spl196000 case VM_Ioctl:
83197567SXin.Chen@Sun.COM fib_cmd = sub_cmd;
83207567SXin.Chen@Sun.COM cmdstr = subcmdstr;
83217567SXin.Chen@Sun.COM sub_cmd = (uint32_t)-1;
83227567SXin.Chen@Sun.COM subcmdstr = NULL;
83237567SXin.Chen@Sun.COM
83247567SXin.Chen@Sun.COM sub_cmd = ddi_get32(acc,
83257567SXin.Chen@Sun.COM (void *)&(((uint32_t *)(void *)&fibp->data[0])[4]));
83265678Spl196000 subcmdstr = aac_cmd_name(sub_cmd, aac_ioctl_subcmds);
83275678Spl196000 break;
83287567SXin.Chen@Sun.COM
83297567SXin.Chen@Sun.COM case VM_CtBlockRead:
83307567SXin.Chen@Sun.COM case VM_CtBlockWrite: {
83317567SXin.Chen@Sun.COM struct aac_blockread *br =
83327567SXin.Chen@Sun.COM (struct aac_blockread *)fibp->data;
83337567SXin.Chen@Sun.COM struct aac_sg_table *sg = &br->SgMap;
83347567SXin.Chen@Sun.COM uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
83357567SXin.Chen@Sun.COM
83367567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE,
83377567SXin.Chen@Sun.COM "FIB> %s Container %d 0x%x/%d", subcmdstr,
83387567SXin.Chen@Sun.COM ddi_get32(acc, &br->ContainerId),
83397567SXin.Chen@Sun.COM ddi_get32(acc, &br->BlockNumber),
83407567SXin.Chen@Sun.COM ddi_get32(acc, &br->ByteCount));
83417567SXin.Chen@Sun.COM for (i = 0; i < sgcount; i++)
83427567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE,
83437567SXin.Chen@Sun.COM " %d: 0x%08x/%d", i,
83447567SXin.Chen@Sun.COM ddi_get32(acc, &sg->SgEntry[i].SgAddress),
83457567SXin.Chen@Sun.COM ddi_get32(acc, &sg->SgEntry[i]. \
83467567SXin.Chen@Sun.COM SgByteCount));
83477567SXin.Chen@Sun.COM return;
83487567SXin.Chen@Sun.COM }
83495678Spl196000 }
83505678Spl196000 break;
83515678Spl196000
83527567SXin.Chen@Sun.COM case ContainerCommand64: {
83537567SXin.Chen@Sun.COM struct aac_blockread64 *br =
83547567SXin.Chen@Sun.COM (struct aac_blockread64 *)fibp->data;
83557567SXin.Chen@Sun.COM struct aac_sg_table64 *sg = &br->SgMap64;
83567567SXin.Chen@Sun.COM uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
83577567SXin.Chen@Sun.COM uint64_t sgaddr;
83587567SXin.Chen@Sun.COM
83597567SXin.Chen@Sun.COM sub_cmd = br->Command;
83607567SXin.Chen@Sun.COM subcmdstr = NULL;
83617567SXin.Chen@Sun.COM if (sub_cmd == VM_CtHostRead64)
83627567SXin.Chen@Sun.COM subcmdstr = "VM_CtHostRead64";
83637567SXin.Chen@Sun.COM else if (sub_cmd == VM_CtHostWrite64)
83647567SXin.Chen@Sun.COM subcmdstr = "VM_CtHostWrite64";
83657567SXin.Chen@Sun.COM else
83667567SXin.Chen@Sun.COM break;
83677567SXin.Chen@Sun.COM
83687567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE,
83697567SXin.Chen@Sun.COM "FIB> %s Container %d 0x%x/%d", subcmdstr,
83707567SXin.Chen@Sun.COM ddi_get16(acc, &br->ContainerId),
83717567SXin.Chen@Sun.COM ddi_get32(acc, &br->BlockNumber),
83727567SXin.Chen@Sun.COM ddi_get16(acc, &br->SectorCount));
83737567SXin.Chen@Sun.COM for (i = 0; i < sgcount; i++) {
83747567SXin.Chen@Sun.COM sgaddr = ddi_get64(acc,
83757567SXin.Chen@Sun.COM &sg->SgEntry64[i].SgAddress);
83767567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE,
83777567SXin.Chen@Sun.COM " %d: 0x%08x.%08x/%d", i,
83787567SXin.Chen@Sun.COM AAC_MS32(sgaddr), AAC_LS32(sgaddr),
83797567SXin.Chen@Sun.COM ddi_get32(acc, &sg->SgEntry64[i]. \
83807567SXin.Chen@Sun.COM SgByteCount));
83817567SXin.Chen@Sun.COM }
83827567SXin.Chen@Sun.COM return;
83837567SXin.Chen@Sun.COM }
83847567SXin.Chen@Sun.COM
83857567SXin.Chen@Sun.COM case RawIo: {
83867567SXin.Chen@Sun.COM struct aac_raw_io *io = (struct aac_raw_io *)fibp->data;
83877567SXin.Chen@Sun.COM struct aac_sg_tableraw *sg = &io->SgMapRaw;
83887567SXin.Chen@Sun.COM uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
83897567SXin.Chen@Sun.COM uint64_t sgaddr;
83907567SXin.Chen@Sun.COM
83917567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE,
83927567SXin.Chen@Sun.COM "FIB> RawIo Container %d 0x%llx/%d 0x%x",
83937567SXin.Chen@Sun.COM ddi_get16(acc, &io->ContainerId),
83947567SXin.Chen@Sun.COM ddi_get64(acc, &io->BlockNumber),
83957567SXin.Chen@Sun.COM ddi_get32(acc, &io->ByteCount),
83967567SXin.Chen@Sun.COM ddi_get16(acc, &io->Flags));
83977567SXin.Chen@Sun.COM for (i = 0; i < sgcount; i++) {
83987567SXin.Chen@Sun.COM sgaddr = ddi_get64(acc, &sg->SgEntryRaw[i].SgAddress);
83997567SXin.Chen@Sun.COM aac_printf(softs, CE_NOTE, " %d: 0x%08x.%08x/%d", i,
84007567SXin.Chen@Sun.COM AAC_MS32(sgaddr), AAC_LS32(sgaddr),
84017567SXin.Chen@Sun.COM ddi_get32(acc, &sg->SgEntryRaw[i].SgByteCount));
84027567SXin.Chen@Sun.COM }
84037567SXin.Chen@Sun.COM return;
84047567SXin.Chen@Sun.COM }
84057567SXin.Chen@Sun.COM
84065678Spl196000 case ClusterCommand:
84077567SXin.Chen@Sun.COM sub_cmd = ddi_get32(acc,
84087567SXin.Chen@Sun.COM (void *)&(((uint32_t *)(void *)fibp->data)[0]));
84095678Spl196000 subcmdstr = aac_cmd_name(sub_cmd, aac_cl_subcmds);
84105678Spl196000 break;
84115678Spl196000
84125678Spl196000 case AifRequest:
84137567SXin.Chen@Sun.COM sub_cmd = ddi_get32(acc,
84147567SXin.Chen@Sun.COM (void *)&(((uint32_t *)(void *)fibp->data)[0]));
84155678Spl196000 subcmdstr = aac_cmd_name(sub_cmd, aac_aif_subcmds);
84165678Spl196000 break;
84175678Spl196000
84185678Spl196000 default:
84195678Spl196000 break;
84205678Spl196000 }
84215678Spl196000
84227567SXin.Chen@Sun.COM fib_size = ddi_get16(acc, &(fibp->Header.Size));
84235678Spl196000 if (subcmdstr)
84245678Spl196000 aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
84255678Spl196000 subcmdstr, fib_size);
84267567SXin.Chen@Sun.COM else if (cmdstr && sub_cmd == (uint32_t)-1)
84275678Spl196000 aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
84285678Spl196000 cmdstr, fib_size);
84295678Spl196000 else if (cmdstr)
84305678Spl196000 aac_printf(softs, CE_NOTE, "FIB> %s: Unknown(0x%x), sz=%d",
84315678Spl196000 cmdstr, sub_cmd, fib_size);
84325678Spl196000 else
84335678Spl196000 aac_printf(softs, CE_NOTE, "FIB> Unknown(0x%x), sz=%d",
84345678Spl196000 fib_cmd, fib_size);
84355678Spl196000 }
84365678Spl196000
84375678Spl196000 static void
aac_print_aif(struct aac_softstate * softs,struct aac_aif_command * aif)84385678Spl196000 aac_print_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
84395678Spl196000 {
84405678Spl196000 int aif_command;
84415678Spl196000 uint32_t aif_seqnumber;
84425678Spl196000 int aif_en_type;
84435678Spl196000 char *str;
84445678Spl196000
84455678Spl196000 aif_command = LE_32(aif->command);
84465678Spl196000 aif_seqnumber = LE_32(aif->seqNumber);
84475678Spl196000 aif_en_type = LE_32(aif->data.EN.type);
84485678Spl196000
84495678Spl196000 switch (aif_command) {
84505678Spl196000 case AifCmdEventNotify:
84515678Spl196000 str = aac_cmd_name(aif_en_type, aac_aifens);
84525678Spl196000 if (str)
84535678Spl196000 aac_printf(softs, CE_NOTE, "AIF! %s", str);
84545678Spl196000 else
84555678Spl196000 aac_printf(softs, CE_NOTE, "AIF! Unknown(0x%x)",
84565678Spl196000 aif_en_type);
84575678Spl196000 break;
84585678Spl196000
84595678Spl196000 case AifCmdJobProgress:
84605678Spl196000 switch (LE_32(aif->data.PR[0].status)) {
84615678Spl196000 case AifJobStsSuccess:
84625678Spl196000 str = "success"; break;
84635678Spl196000 case AifJobStsFinished:
84645678Spl196000 str = "finished"; break;
84655678Spl196000 case AifJobStsAborted:
84665678Spl196000 str = "aborted"; break;
84675678Spl196000 case AifJobStsFailed:
84685678Spl196000 str = "failed"; break;
84695678Spl196000 case AifJobStsSuspended:
84705678Spl196000 str = "suspended"; break;
84715678Spl196000 case AifJobStsRunning:
84725678Spl196000 str = "running"; break;
84735678Spl196000 default:
84745678Spl196000 str = "unknown"; break;
84755678Spl196000 }
84765678Spl196000 aac_printf(softs, CE_NOTE,
84775678Spl196000 "AIF! JobProgress (%d) - %s (%d, %d)",
84785678Spl196000 aif_seqnumber, str,
84795678Spl196000 LE_32(aif->data.PR[0].currentTick),
84805678Spl196000 LE_32(aif->data.PR[0].finalTick));
84815678Spl196000 break;
84825678Spl196000
84835678Spl196000 case AifCmdAPIReport:
84845678Spl196000 aac_printf(softs, CE_NOTE, "AIF! APIReport (%d)",
84855678Spl196000 aif_seqnumber);
84865678Spl196000 break;
84875678Spl196000
84885678Spl196000 case AifCmdDriverNotify:
84895678Spl196000 aac_printf(softs, CE_NOTE, "AIF! DriverNotify (%d)",
84905678Spl196000 aif_seqnumber);
84915678Spl196000 break;
84925678Spl196000
84935678Spl196000 default:
84945678Spl196000 aac_printf(softs, CE_NOTE, "AIF! AIF %d (%d)",
84955678Spl196000 aif_command, aif_seqnumber);
84965678Spl196000 break;
84975678Spl196000 }
84985678Spl196000 }
84995678Spl196000
85005678Spl196000 #endif /* DEBUG */
8501