Hi there, >From ching Huang <[email protected]> This patch is against to http://bxr.su/OpenBSD/sys/dev/pci/arc.c 1. Adjust some code to meet coding style and have more readability. 2. Add new code for ARC-1203, 1200, 1201 series, they are belong to ARC_HBA_TYPE_B. 3. Add new code for ARC-1884, it belongs to ARC_HBA_TYPE_E. 4. Extract or rewrite some code to a new function for support more adapter type controller and code structure.
Signed-off-by: ching Huang <[email protected]> --- diff -upN a/sys/dev/pci/arc.c b/sys/dev/pci/arc.c --- a/sys/dev/pci/arc.c Mon Jul 6 19:24:58 2020 +++ b/sys/dev/pci/arc.c Mon Jul 6 19:25:30 2020 @@ -17,7 +17,11 @@ */ /* - * Ching Huang Support ARC1880,1882,1213,1223,1214 + * Rev# Date Name Description + * 1.1.0.0 2012/04/18 Ching Huang Support ARC188x,1213,1223,12x5,12x6 + * 1.2.0.0 2012/11/14 Ching Huang Support ARC12x4 + * 1.3.0.0 2016/03/09 Ching Huang Support ARC1200,1201,1203 + * 1.4.0.0 2018/09/05 Ching Huang Support ARC1884 */ #include "bio.h" @@ -61,20 +65,28 @@ int arcdebug = 0; #define DNPRINTF(n, p...) /* n, p */ #endif +#define ARC_VERSION "arc v1.4.0.0-20200623" +#define ARC_ADAPTER_ID 0xff + #define ARC_HBA_TYPE_A 0x00000001 #define ARC_HBA_TYPE_B 0x00000002 #define ARC_HBA_TYPE_C 0x00000003 #define ARC_HBA_TYPE_D 0x00000004 +#define ARC_HBA_TYPE_E 0x00000005 #define ARC_RA_PCI_BAR PCI_MAPREG_START #define ARC_RB_DOORBELL_BAR PCI_MAPREG_START #define ARC_RB_RWBUFFER_BAR PCI_MAPREG_PPB_END #define ARC_RC_PCI_BAR PCI_MAPREG_PCB_END #define ARC_RD_PCI_BAR PCI_MAPREG_START +#define ARC_RE_PCI_BAR PCI_MAPREG_PCB_END +#define ARC_RF_PCI_BAR PCI_MAPREG_START #define ARCMSR_MAX_CCB_COUNT 264 #define ARCMSR_MAX_HBB_POSTQUEUE 264 #define ARCMSR_MAX_HBD_POSTQUEUE 256 +#define ARCMSR_MAX_HBE_COMPLETION_Q 256 +#define ARCMSR_MAX_HBF_COMPLETION_Q 256 /* Areca boards using the Intel IOP are Type A (RA) */ @@ -130,12 +142,53 @@ int arcdebug = 0; /* Areca boards using the Marvel IOP0 are Type B (RB) */ -#define ARC_RB_DRV2IOP_DOORBELL 0x00020400 -#define ARC_RB_DRV2IOP_DOORBELL_MASK 0x00020404 -#define ARC_RB_IOP2DRV_DOORBELL 0x00020408 -#define ARC_RB_IOP2DRV_DOORBELL_FIRMWARE_OK (1<<31) -#define ARC_RB_IOP2DRV_DOORBELL_MASK 0x0002040c +#define ARC_RB_INB_DOORBELL 0x00020400 +#define ARC_RB_INB_DOORBELL_MASK 0x00020404 +#define ARC_RB_OUTB_DOORBELL 0x00020408 +#define ARC_RB_OUTB_DOORBELL_MASK 0x0002040c +#define ARC_RB_OUTB_DOORBELL_FIRMWARE_OK (1<<31) +#define ARC_RB_OUTB_DOORBELL_1203 0x00021870 +#define ARC_RB_OUTB_DOORBELL_MASK_1203 0x00021874 +#define ARC_RB_INB_DOORBELL_1203 0x00021878 +#define ARC_RB_INB_DOORBELL_MASK_1203 0x0002187C + +#define ARC_RB_INB_MSG0_GET_CONFIG 0x00010008 +#define ARC_RB_INB_MSG0_SET_CONFIG 0x00020008 +#define ARC_RB_INB_MSG0_ABORT_CMD 0x00030008 +#define ARC_RB_INB_MSG0_STOP_BGRB 0x00040008 +#define ARC_RB_INB_MSG0_FLUSH_CACHE 0x00050008 +#define ARC_RB_INB_MSG0_START_BGRB 0x00060008 +#define ARC_RB_INB_MSG0_START_DRIVER_MODE 0x000E0008 +#define ARC_RB_INB_MSG0_SET_POST_WINDOW 0x000F0008 +#define ARC_RB_INB_MSG0_ACTIVE_EOI_MODE 0x00100008 +#define ARC_RB_INB_MSG0_FIRMWARE_OK 0x80000000 + +#define ARC_RB_I2D_DATA_WRITE_OK 0x00000001 +#define ARC_RB_I2D_DATA_READ_OK 0x00000002 +#define ARC_RB_I2D_CDB_DONE 0x00000004 +#define ARC_RB_I2D_MSG_CMD_DONE 0x00000008 +#define ARC_RB_I2D_INTR_ENABLE_DOORBELL 0x0000000F +#define ARC_RB_I2D_DOORBELL_INT 0x0000000B +#define ARC_RB_I2D_POSTQ_INT 0x00000004 + +#define ARC_RB_D2I_DATA_WRITE_OK 0x00000001 +#define ARC_RB_D2I_DATA_READ_OK 0x00000002 +#define ARC_RB_D2I_CDB_POSTED 0x00000004 +#define ARC_RB_D2I_MSG_CMD_POSTED 0x00000008 +#define ARC_RB_D2I_END_OF_INTERRUPT 0x00000010 + +#define ARC_RB_DOORBELL_HANDLE_INT 0x0000000F +#define ARC_RB_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0 +#define ARC_RB_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7 + +/* data tunnel buffer between user space and firmware */ +#define ARC_RB_MSG_RWBUF 0x0000fa00 /* iop message_rwbuffer for message command */ +#define ARC_RB_MSG_WBUF 0x0000fe00 /* user space data to iop 128bytes */ +#define ARC_RB_MSG_RBUF 0x0000ff00 /* iop data to user space 128bytes */ + +#define ARC_RB_REPLY_QUEUE_ERR (1<<28) + /* Areca boards using the LSI IOP are Type C (RC) */ #define ARC_RC_INB_DOORBELL 0x20 @@ -258,6 +311,57 @@ int arcdebug = 0; #define ARC_RD_REPLY_QUEUE_ERR 1 #define ARC_RD_OUTB_LIST_INT_CLR 1 +/* Areca boards using the LSI IOP are Type E (RE) */ +#define ARC_SIGNATURE_1884 0x188417D3 + +#define ARC_RE_INB_DOORBELL 0x00 +#define ARC_RE_OUTB_DOORBELL 0x00 +#define ARC_RE_INTR_STAT 0x30 +#define ARC_RE_INTR_MASK 0x34 +#define ARC_RE_D2I_MSG_CMD_DONE 0x08 +#define ARC_RE_I2D_MSG_CMD_DONE 0x08 +#define ARC_RE_REPLY_PRODUCER_INDEX 0x68 +#define ARC_RE_REPLY_CONSUMER_INDEX 0x6C +#define ARC_RE_INB_MSGADDR0 0xB0 +#define ARC_RE_INB_MSGADDR1 0xB4 +#define ARC_RE_OUTB_MSGADDR0 0xB8 +#define ARC_RE_OUTB_MSGADDR1 0xBC +#define ARC_RE_INB_POSTQ_LOW 0xC0 +#define ARC_RE_INB_POSTQ_HIGH 0xC4 +#define ARC_RE_OUTB_REPLYQ_LOW 0xC8 +#define ARC_RE_OUTB_REPLYQ_HIGH 0xCC +#define ARC_RE_MSG_WBUF_LEN 0x2000 +#define ARC_RE_MSG_WBUF 0x2004 +#define ARC_RE_MSG_RBUF_LEN 0x2100 +#define ARC_RE_MSG_RBUF 0x2104 +#define ARC_RE_MSG_RWBUF 0x2200 + +#define ARC_RE_INB_MSG0_NOP (0x00000000) +#define ARC_RE_INB_MSG0_GET_CONFIG (0x00000001) +#define ARC_RE_INB_MSG0_SET_CONFIG (0x00000002) +#define ARC_RE_INB_MSG0_ABORT_CMD (0x00000003) +#define ARC_RE_INB_MSG0_STOP_BGRB (0x00000004) +#define ARC_RE_INB_MSG0_FLUSH_CACHE (0x00000005) +#define ARC_RE_INB_MSG0_START_BGRB (0x00000006) +#define ARC_RE_INB_MSG0_SYNC_TIMER (0x00000008) +#define ARC_RE_DOORBELL_SYNC (0x00000100) + +#define ARC_RE_D2I_DATA_WRITE_OK 0x00000002 +#define ARC_RE_D2I_DATA_READ_OK 0x00000004 +#define ARC_RE_D2I_MESSAGE_CMD_DONE 0x00000008 +#define ARC_RE_I2D_DATA_WRITE_OK 0x00000002 +#define ARC_RE_I2D_DATA_READ_OK 0x00000004 +#define ARC_RE_I2D_MESSAGE_CMD_DONE 0x00000008 +#define ARC_RE_MESSAGE_FIRMWARE_OK 0x80000000 +#define ARC_RE_OUTB_MSG_FIRMWARE_OK 0x80000000 + +#define ARC_RE_INTR_STAT_DOORBELL (1<<0) +#define ARC_RE_INTR_STAT_POSTQUEUE (1<<3) +#define ARC_RE_INTR_MASK_ALL 0x00000009 +#define ARC_RE_INTR_MASK_DOORBELL (1<<0) +#define ARC_RE_INTR_MASK_POSTQUEUE (1<<3) +#define ARC_RE_REPLY_QUEUE_ERR 1 + struct arc_msg_firmware_info { u_int32_t signature; #define ARC_FWINFO_SIGNATURE_GET_CONFIG (0x87974060) @@ -443,6 +547,15 @@ struct arc_iop; struct arc_ccb; SLIST_HEAD(arc_ccb_list, arc_ccb); +struct arc_HBB_Msgu { + u_int32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; + u_int32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; + u_int32_t postq_index; + u_int32_t doneq_index; +}; + +#define ARC_HBB_CMDQ_PTR_LEN sizeof(struct arc_HBB_Msgu) + struct InBound_SRB { u_int32_t addressLow; /* pointer to SRB block */ u_int32_t addressHigh; @@ -456,14 +569,25 @@ struct OutBound_SRB { }; struct arc_HBD_Msgu { - struct InBound_SRB post_qbuffer[ARCMSR_MAX_HBD_POSTQUEUE]; - struct OutBound_SRB done_qbuffer[ARCMSR_MAX_HBD_POSTQUEUE+1]; + struct InBound_SRB post_qbuffer[ARCMSR_MAX_HBD_POSTQUEUE]; + struct OutBound_SRB done_qbuffer[ARCMSR_MAX_HBD_POSTQUEUE+1]; u_int16_t postq_index; u_int16_t doneq_index; }; -#define ARC_MAX_CMDQ_PTR_LEN sizeof(struct arc_HBD_Msgu) +#define ARC_HBD_CMDQ_PTR_LEN sizeof(struct arc_HBD_Msgu) +struct arc_HBE_Msgu { + u_int16_t cmdFlag; + u_int16_t cmdSMID; + u_int16_t cmdLMID; // reserved (0) + u_int16_t cmdFlag2; // reserved (0) +}; + +#define ARC_HBE_COMPLETION_Q_LEN (sizeof(struct arc_HBE_Msgu) * ARCMSR_MAX_HBE_COMPLETION_Q + 128) +#define ARC_HBF_COMPLETION_Q_LEN ARC_HBE_COMPLETION_Q_LEN +#define ARC_HBF_MESG_BUFFER_SIZE (256 * 3) + struct arc_msg_scsicmd { u_int8_t bus; u_int8_t target; @@ -476,7 +600,7 @@ struct arc_msg_scsicmd { #define ARC_MSG_SCSICMD_FLAG_SGL_BSIZE_512 (1<<0) #define ARC_MSG_SCSICMD_FLAG_FROM_BIOS (1<<1) #define ARC_MSG_SCSICMD_FLAG_WRITE (1<<2) -#define ARC_MSG_SCSICMD_FLAG_SIMPLEQ (0x00) +#define ARC_MSG_SCSICMD_FLAG_SIMPLEQ (0x00) #define ARC_MSG_SCSICMD_FLAG_HEADQ (0x08) #define ARC_MSG_SCSICMD_FLAG_ORDERQ (0x10) u_int8_t msgPages; @@ -510,20 +634,19 @@ struct arc_sge { #define ARC_BLOCKSIZE 512 /* the firmware deals with up to 256 or 512 byte command frames. */ -/* sizeof(struct arc_msg_scsicmd) + (sizeof(struct arc_sge) * 38) == 508 */ +/* sizeof(struct arc_msg_scsicmd) + (sizeof(struct arc_sge) * 38) == 504 */ #define ARC_SGL_MAXLEN 38 /* sizeof(struct arc_msg_scsicmd) + (sizeof(struct arc_sge) * 17) == 252 */ #define ARC_SGL_256LEN 17 struct arc_io_cmd { struct arc_msg_scsicmd cmd; - struct arc_sge sgl[ARC_SGL_MAXLEN]; + struct arc_sge sgl[ARC_SGL_MAXLEN]; u_int32_t reserved1; - struct arc_ccb *ccb; - u_int32_t reserved2[6]; + u_int32_t ccb_id; } __packed; -#define ARC_IO_CMD_LEN 512+32 +#define ARC_IO_CMD_LEN (sizeof(struct arc_io_cmd)) /* stuff to manage a scsi command */ struct arc_ccb { @@ -538,11 +661,12 @@ struct arc_ccb { SLIST_ENTRY(arc_ccb) ccb_link; u_int32_t arc_io_cmd_length; + u_int32_t smid; + u_int32_t ccb_id; }; struct arc_softc { struct device sc_dev; - const struct arc_iop *sc_iop; struct scsi_link sc_link; pci_chipset_tag_t sc_pc; @@ -574,11 +698,39 @@ struct arc_softc { u_int32_t sc_ledmask; u_int32_t sc_adp_type; + u_int32_t sc_ccb_phys_lo; u_int32_t sc_ccb_phys_hi; u_int32_t postQ_buffer; u_int32_t doneQ_buffer; bus_addr_t cmdQ_ptr_offset; - struct arc_HBD_Msgu *pmu; + union { + struct arc_HBB_Msgu *pmuB; + struct arc_HBD_Msgu *pmu; + struct arc_HBE_Msgu *pmuE; + struct arc_HBE_Msgu *pmuF; + }; + bus_space_tag_t sc_msgt; + bus_space_handle_t sc_msgh; + bus_size_t sc_msgs; + bus_size_t inb_doorbell; + bus_size_t inb_doorbell_mask; + bus_size_t outb_doorbell; + bus_size_t outb_doorbell_mask; + u_int32_t sc_int_mask; + pcireg_t ab_product; + u_int32_t doneq_index; + u_int32_t doneq_size; + u_int32_t doneq_entry; + u_int32_t doneq_phys_lo; + u_int32_t doneq_phys_hi; + u_int32_t in_doorbell; + u_int32_t out_doorbell; + u_int32_t *message_wbuffer; + u_int32_t *message_rbuffer; + u_int32_t *msgcode_rwbuffer; + u_int32_t msgBuf_phys_lo; + u_int32_t msgBuf_phys_hi; + u_int32_t ioc_compq_size; }; #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) @@ -599,51 +751,61 @@ int arc_detach(struct device *, int); int arc_activate(struct device *, int); int arc_intr(void *); int arc_intr_A(void *); +int arc_intr_B(void *); int arc_intr_C(void *); int arc_intr_D(void *); +int arc_intr_E(void *); /* interface for scsi midlayer to talk to */ void arc_scsi_cmd(struct scsi_xfer *); +void arc_minphys(struct buf *, struct scsi_link *); /* code to deal with getting bits in and out of the bus space */ u_int32_t arc_read(struct arc_softc *, bus_size_t); void arc_read_region(struct arc_softc *, bus_size_t, - void *, size_t); + void *, size_t); void arc_write(struct arc_softc *, bus_size_t, u_int32_t); void arc_write_region(struct arc_softc *, bus_size_t, - void *, size_t); -int arc_wait_eq(struct arc_softc *, bus_size_t, - u_int32_t, u_int32_t); -int arc_wait_ne(struct arc_softc *, bus_size_t, - u_int32_t, u_int32_t); -int arc_msg0(struct arc_softc *, u_int32_t); + void *, size_t); +int arc_wait_eq(struct arc_softc *, bus_size_t, + u_int32_t, u_int32_t); +int arc_wait_ne(struct arc_softc *, bus_size_t, + u_int32_t, u_int32_t); +int arc_msg0(struct arc_softc *, u_int32_t); +u_int32_t arc_read2(struct arc_softc *, bus_size_t); +void arc_read_region2(struct arc_softc *, bus_size_t, + void *, size_t); +void arc_write2(struct arc_softc *, bus_size_t, u_int32_t); +void arc_write_region2(struct arc_softc *, bus_size_t, + void *, size_t); struct arc_dmamem *arc_dmamem_alloc(struct arc_softc *, size_t); void arc_dmamem_free(struct arc_softc *, struct arc_dmamem *); -void arc_free_ccb_src(struct arc_softc *sc); +void arc_free_ccb_src(struct arc_softc *sc); -int arc_alloc_ccbs(struct arc_softc *); +int arc_alloc_ccbs(struct arc_softc *); struct arc_ccb *arc_get_ccb(struct arc_softc *); void arc_put_ccb(struct arc_softc *, struct arc_ccb *); -int arc_load_xs(struct arc_ccb *); -int arc_complete(struct arc_softc *, struct arc_ccb *, - int); +int arc_load_xs(struct arc_ccb *); +int arc_complete(struct arc_softc *, struct arc_ccb *, + int); void arc_scsi_cmd_done(struct arc_softc *, struct arc_ccb *, - u_int32_t); + u_int32_t); -int arc_map_pci_resources(struct arc_softc *, - struct pci_attach_args *); +int arc_map_pci_resources(struct arc_softc *, + struct pci_attach_args *); void arc_unmap_pci_resources(struct arc_softc *); -int arc_chipA_firmware(struct arc_softc *); -int arc_chipB_firmware(struct arc_softc *); -int arc_chipC_firmware(struct arc_softc *); -int arc_chipD_firmware(struct arc_softc *); +int arc_query_firmware(struct arc_softc *); void arc_enable_all_intr(struct arc_softc *); void arc_disable_all_intr(struct arc_softc *); void arc_stop_bgrb_proc(struct arc_softc *sc); void arc_flush_cache(struct arc_softc *sc); void arc_iop_set_conf(struct arc_softc *sc); +int arc_start_bkgrnd_rebuild(struct arc_softc *); +int arc_get_firmware_config(struct arc_softc *, + struct arc_msg_firmware_info *); +void arc_clear_doorbell_qbuffer(struct arc_softc *); #if NBIO > 0 /* stuff to do messaging via the doorbells */ @@ -651,30 +813,29 @@ void arc_lock(struct arc_softc *); void arc_unlock(struct arc_softc *); void arc_wait(struct arc_softc *); u_int8_t arc_msg_cksum(void *, u_int16_t); -int arc_msgbuf(struct arc_softc *, void *, size_t, - void *, size_t, int); +int arc_msgbuf(struct arc_softc *, void *, size_t, + void *, size_t, int); /* bioctl */ -int arc_bioctl(struct device *, u_long, caddr_t); -int arc_bio_inq(struct arc_softc *, struct bioc_inq *); -int arc_bio_vol(struct arc_softc *, struct bioc_vol *); -int arc_bio_disk(struct arc_softc *, struct bioc_disk *); -int arc_bio_alarm(struct arc_softc *, struct bioc_alarm *); -int arc_bio_alarm_state(struct arc_softc *, - struct bioc_alarm *); -int arc_bio_blink(struct arc_softc *, struct bioc_blink *); +int arc_bioctl(struct device *, u_long, caddr_t); +int arc_bio_inq(struct arc_softc *, struct bioc_inq *); +int arc_bio_vol(struct arc_softc *, struct bioc_vol *); +int arc_bio_disk(struct arc_softc *, struct bioc_disk *); +int arc_bio_alarm(struct arc_softc *, struct bioc_alarm *); +int arc_bio_alarm_state(struct arc_softc *, + struct bioc_alarm *); +int arc_bio_blink(struct arc_softc *, struct bioc_blink *); +int arc_bio_getvol(struct arc_softc *, int, + struct arc_fw_volinfo *); -int arc_bio_getvol(struct arc_softc *, int, - struct arc_fw_volinfo *); - #ifndef SMALL_KERNEL struct arc_task { struct task t; struct arc_softc *sc; }; /* sensors */ -void arc_create_sensors(void *); -void arc_refresh_sensors(void *); +void arc_create_sensors(void *); +void arc_refresh_sensors(void *); #endif /* SMALL_KERNEL */ #endif @@ -692,63 +853,47 @@ struct scsi_adapter arc_switch = { }; /* real stuff for dealing with the hardware */ -struct arc_iop { - int (*iop_query_firmware)(struct arc_softc *); -}; -static const struct arc_iop arc_intel = { - arc_chipA_firmware -}; - -static const struct arc_iop arc_marvell = { - arc_chipB_firmware -}; - -static const struct arc_iop arc_lsi = { - arc_chipC_firmware -}; - -static const struct arc_iop arc_marvell2 = { - arc_chipD_firmware -}; - struct arc_board { pcireg_t ab_vendor; pcireg_t ab_product; - const struct arc_iop *ab_iop; + u_int16_t ab_io_type; }; const struct arc_board *arc_match_board(struct pci_attach_args *); -static const struct arc_board arc_devices[] = { - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1110, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1120, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1130, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1160, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1170, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1200, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1200_B, &arc_marvell }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1202, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1210, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1214, &arc_marvell2 }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1220, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1230, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1260, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1270, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1280, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1380, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1381, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1680, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1681, &arc_intel }, - { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1880, &arc_lsi } +const struct arc_board arc_devices[] = { + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1110, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1120, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1130, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1160, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1170, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1200, ARC_HBA_TYPE_B }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1200_B, ARC_HBA_TYPE_B }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1202, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1203, ARC_HBA_TYPE_B }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1210, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1214, ARC_HBA_TYPE_D }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1220, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1230, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1260, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1270, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1280, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1380, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1381, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1680, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1681, ARC_HBA_TYPE_A }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1880, ARC_HBA_TYPE_C }, + { PCI_VENDOR_ARECA, PCI_PRODUCT_ARECA_ARC1884, ARC_HBA_TYPE_E } }; const struct arc_board * arc_match_board(struct pci_attach_args *pa) { const struct arc_board *ab; - int i; + int i, j; - for (i = 0; i < sizeof(arc_devices) / sizeof(arc_devices[0]); i++) { + j = sizeof(arc_devices) / sizeof(arc_devices[0]); + for (i = 0; i < j; i++) { ab = &arc_devices[i]; if (PCI_VENDOR(pa->pa_id) == ab->ab_vendor && @@ -765,6 +910,38 @@ arc_match(struct device *parent, void *match, void *au return ((arc_match_board(aux) == NULL) ? 0 : 1); } +int +arc_wait_firmware_ready(struct arc_softc *sc) +{ + int ready; + + switch(sc->sc_adp_type) { + case ARC_HBA_TYPE_A: + ready = arc_wait_eq(sc, ARC_RA_OUTB_ADDR1, ARC_RA_OUTB_ADDR1_FIRMWARE_OK, + ARC_RA_OUTB_ADDR1_FIRMWARE_OK); + break; + case ARC_HBA_TYPE_B: + ready = arc_wait_eq(sc, sc->outb_doorbell, ARC_RB_OUTB_DOORBELL_FIRMWARE_OK, + ARC_RB_OUTB_DOORBELL_FIRMWARE_OK); + break; + case ARC_HBA_TYPE_C: + ready = arc_wait_eq(sc, ARC_RC_OUTB_MSGADDR1, ARC_RC_OUTB_MSG_FIRMWARE_OK, + ARC_RC_OUTB_MSG_FIRMWARE_OK); + break; + case ARC_HBA_TYPE_D: + ready = arc_wait_eq(sc, ARC_RD_OUTB_MSGADDR1, ARC_RD_OUTB_MSG_FIRMWARE_OK, + ARC_RD_OUTB_MSG_FIRMWARE_OK); + break; + case ARC_HBA_TYPE_E: + ready = arc_wait_eq(sc, ARC_RE_OUTB_MSGADDR1, ARC_RE_OUTB_MSG_FIRMWARE_OK, + ARC_RE_OUTB_MSG_FIRMWARE_OK); + break; + } + if (ready != 0) + printf("%s: timeout waiting for firmware ok\n", DEVNAME(sc)); + return (ready); +} + void arc_attach(struct device *parent, struct device *self, void *aux) { @@ -772,36 +949,41 @@ arc_attach(struct device *parent, struct device *self, struct pci_attach_args *pa = aux; struct scsibus_attach_args saa; struct device *child; + const struct arc_board *ab; sc->sc_talking = 0; rw_init(&sc->sc_lock, "arcmsg"); - sc->sc_iop = arc_match_board(pa)->ab_iop; - if(sc->sc_iop == &arc_intel) - sc->sc_adp_type = ARC_HBA_TYPE_A; - else if(sc->sc_iop == &arc_marvell) - sc->sc_adp_type = ARC_HBA_TYPE_B; - else if(sc->sc_iop == &arc_lsi) - sc->sc_adp_type = ARC_HBA_TYPE_C; - else if(sc->sc_iop == &arc_marvell2) - sc->sc_adp_type = ARC_HBA_TYPE_D; + ab = arc_match_board(pa); + sc->sc_adp_type = ab->ab_io_type; if (arc_map_pci_resources(sc, pa) != 0) { /* error message printed by arc_map_pci_resources */ return; } + sc->ab_product = ab->ab_product; if (arc_alloc_ccbs(sc) != 0) { /* error message printed by arc_alloc_ccbs */ goto unmap_pci; } - arc_iop_set_conf(sc); + arc_wait_firmware_ready(sc); - if (sc->sc_iop->iop_query_firmware(sc) != 0) { + if (arc_query_firmware(sc) != 0) { /* error message printed by arc_query_firmware */ - goto unmap_pci; + goto free_ccb; } + arc_iop_set_conf(sc); + + if (arc_start_bkgrnd_rebuild(sc)) { + printf("%s: timeout waiting to start bg rebuild\n", + DEVNAME(sc)); + goto free_ccb; + } + + arc_clear_doorbell_qbuffer(sc); + sc->sc_link.adapter = &arc_switch; sc->sc_link.adapter_softc = sc; sc->sc_link.adapter_target = SDEV_NO_ADAPTER_TARGET; @@ -809,6 +991,7 @@ arc_attach(struct device *parent, struct device *self, sc->sc_link.openings = sc->sc_req_count; sc->sc_link.pool = &sc->sc_iopool; + bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link; child = config_found(self, &saa, scsiprint); @@ -839,6 +1022,8 @@ arc_attach(struct device *parent, struct device *self, #endif return; +free_ccb: + arc_free_ccb_src(sc); unmap_pci: arc_unmap_pci_resources(sc); } @@ -867,6 +1052,9 @@ arc_detach(struct device *self, int flags) arc_stop_bgrb_proc(sc); arc_flush_cache(sc); + arc_disable_all_intr(sc); + arc_free_ccb_src(sc); + arc_unmap_pci_resources(sc); return (0); } @@ -909,10 +1097,10 @@ arc_intr_A(void *arg) cmd = (struct arc_io_cmd *)(kva + ((reg << ARC_RA_REPLY_QUEUE_ADDR_SHIFT) - (u_int32_t)ARC_DMA_DVA(sc->sc_requests))); - ccb = cmd->ccb; + ccb = &sc->sc_ccbs[cmd->ccb_id]; bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - ccb->cmd_dma_offset, ARC_MAX_IOCMDLEN, + ccb->cmd_dma_offset, ARC_IO_CMD_LEN, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); error = (reg & ARC_RA_REPLY_QUEUE_ERR)? 1:0; @@ -923,6 +1111,78 @@ arc_intr_A(void *arg) } int +arc_intr_B(void *arg) +{ + struct arc_softc *sc = arg; + struct arc_ccb *ccb = NULL; + char *kva = ARC_DMA_KVA(sc->sc_requests); + struct arc_io_cmd *cmd; + u_int32_t reg, intrstat, error; + u_int32_t doneq_index; + int ret = 0; + struct arc_HBB_Msgu *pmuB; + + intrstat = arc_read(sc, sc->outb_doorbell) & ARC_RB_I2D_INTR_ENABLE_DOORBELL; + if (!intrstat) + return (ret); + + arc_write(sc, sc->outb_doorbell, ~intrstat); + arc_write(sc, sc->inb_doorbell, ARC_RB_D2I_END_OF_INTERRUPT); + if (intrstat & ARC_RB_I2D_DOORBELL_INT) { + ret = 1; + if (sc->sc_talking) { + /* if an ioctl is talking, wake it up */ + arc_write(sc, sc->outb_doorbell_mask, ARC_RB_I2D_CDB_DONE); + wakeup(sc); + } else { + /* otherwise drop it */ + if (intrstat & ARC_RB_I2D_DATA_WRITE_OK) { + arc_write(sc, sc->inb_doorbell, + ARC_RB_I2D_DATA_READ_OK); + } +/* if (intrstat & ARC_RB_I2D_DATA_READ_OK) { + arc_write(sc, sc->inb_doorbell, + ARC_RB_D2I_DATA_WRITE_OK); + } +*/ + if (intrstat & ARC_RB_I2D_MSG_CMD_DONE) { + arc_write(sc, sc->outb_doorbell, + ARC_RB_MESSAGE_INT_CLEAR_PATTERN); + } + + } + } + + if (intrstat & ARC_RB_I2D_POSTQ_INT) { + ret = 1; + bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), + sc->cmdQ_ptr_offset, ARC_HBB_CMDQ_PTR_LEN, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + pmuB = sc->pmuB; + doneq_index = pmuB->doneq_index; + while ((reg = pmuB->done_qbuffer[doneq_index]) != 0) { + if (doneq_index >= 4) + pmuB->done_qbuffer[doneq_index - 4] = 0; + else + pmuB->done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE - (4 - doneq_index)] = 0; + cmd = (struct arc_io_cmd *)(kva + + ((reg << ARC_RA_REPLY_QUEUE_ADDR_SHIFT) - + (u_int32_t)ARC_DMA_DVA(sc->sc_requests))); + ccb = &sc->sc_ccbs[cmd->ccb_id]; + bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), + ccb->cmd_dma_offset, ARC_IO_CMD_LEN, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + error = (reg & ARC_RB_REPLY_QUEUE_ERR) ? 1 : 0; + arc_scsi_cmd_done(sc, ccb, error); + doneq_index++; + doneq_index %= ARCMSR_MAX_HBB_POSTQUEUE; + pmuB->doneq_index = doneq_index; + } + } + return (ret); +} + +int arc_intr_C(void *arg) { struct arc_softc *sc = arg; @@ -974,15 +1234,17 @@ arc_intr_C(void *arg) while (arc_read(sc, ARC_RC_INTR_STAT) & ARC_RC_INTR_STAT_POSTQUEUE) { reg = arc_read(sc, ARC_RC_OUTB_REPLYQ_LOW); + if (reg == 0xFFFFFFFF) + break; cmd = (struct arc_io_cmd *)(kva + ((reg & 0xFFFFFFE0) - (u_int32_t)ARC_DMA_DVA(sc->sc_requests))); - ccb = cmd->ccb; + ccb = &sc->sc_ccbs[cmd->ccb_id]; bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - ccb->cmd_dma_offset, ARC_MAX_IOCMDLEN, + ccb->cmd_dma_offset, ARC_IO_CMD_LEN, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - error = (reg & ARC_RC_REPLY_QUEUE_ERR); + error = reg & ARC_RC_REPLY_QUEUE_ERR; arc_scsi_cmd_done(sc, ccb, error); throttling++; if(throttling == ARC_RC_THROTTLE) { @@ -996,7 +1258,7 @@ arc_intr_C(void *arg) return (ret); } -static u_int16_t +u_int16_t arcmsr_get_doneq_index(struct arc_HBD_Msgu *phbdmu) { u_int16_t doneq_index, index_stripped; @@ -1070,7 +1332,7 @@ arc_intr_D(void *arg) ret = 1; arc_write(sc, ARC_RD_OUTB_INTR_CAUSE, ARC_RD_OUTB_LIST_INT_CLR); bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - sc->cmdQ_ptr_offset, ARC_MAX_CMDQ_PTR_LEN, + 0, sc->ioc_compq_size, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); pmu = sc->pmu; ob_write_ptr = pmu->done_qbuffer[0].addressLow; @@ -1079,11 +1341,8 @@ arc_intr_D(void *arg) doneq_index = arcmsr_get_doneq_index(pmu); reg = pmu->done_qbuffer[(doneq_index & 0xFF)+1].addressLow; cmd = (struct arc_io_cmd *)(kva + ((reg & 0xFFFFFFF0) - - (u_int32_t)ARC_DMA_DVA(sc->sc_requests))); - ccb = cmd->ccb; - bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - ccb->cmd_dma_offset, ARC_MAX_IOCMDLEN, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + (u_int32_t)ARC_DMA_DVA(sc->sc_requests))); + ccb = &sc->sc_ccbs[cmd->ccb_id]; error = (reg & ARC_RD_REPLY_QUEUE_ERR); arc_scsi_cmd_done(sc, ccb, error); arc_write(sc, ARC_RD_OUTB_READ_PTR, doneq_index); @@ -1095,6 +1354,79 @@ arc_intr_D(void *arg) } int +arc_intr_E(void *arg) +{ + struct arc_softc *sc = arg; + struct arc_ccb *ccb = NULL; + u_int32_t reg, intrstat, obmsg, error, val; + int ret = 0; + + intrstat = arc_read(sc, ARC_RE_INTR_STAT); + if (!(intrstat & (ARC_RE_INTR_STAT_POSTQUEUE | + ARC_RE_INTR_STAT_DOORBELL))) + return (ret); + + if (intrstat & ARC_RE_INTR_STAT_DOORBELL) { + ret = 1; + if (sc->sc_talking) { + /* if an ioctl is talking, wake it up */ + arc_write(sc, ARC_RE_INTR_MASK, + ~ARC_RE_INTR_MASK_POSTQUEUE); + wakeup(sc); + } else { + /* otherwise drop it */ + reg = arc_read(sc, ARC_RE_OUTB_DOORBELL); + val = sc->in_doorbell ^ reg; + arc_write(sc, ARC_RE_INTR_STAT, 0); + if (val & ARC_RE_I2D_DATA_WRITE_OK) { + sc->out_doorbell ^= ARC_RE_I2D_DATA_READ_OK; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + } +/* if (val & ARC_RE_I2D_DATA_READ_OK) { + sc->out_doorbell ^= ARC_RE_D2I_DATA_WRITE_OK; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + } +*/ + if (val & ARC_RE_I2D_MESSAGE_CMD_DONE) { + obmsg = arc_read(sc, ARC_RE_MSG_RWBUF); + if (obmsg == ARC_FWINFO_SIGNATURE_GET_CONFIG) + ; /* handle devices hot-plug */ + } + + } + } + + if (intrstat & ARC_RE_INTR_STAT_POSTQUEUE) { + u_int16_t cmdSMID; + u_int16_t doneq_index; + ret = 1; + bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), + sc->cmdQ_ptr_offset, ARC_HBE_COMPLETION_Q_LEN, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + while (arc_read(sc, ARC_RE_INTR_STAT) & ARC_RE_INTR_STAT_POSTQUEUE) { + doneq_index = sc->doneq_index; + if ((arc_read(sc, ARC_RE_REPLY_PRODUCER_INDEX) & 0xFFFF) != doneq_index) { + cmdSMID = sc->pmuE[doneq_index].cmdSMID; + ccb = &sc->sc_ccbs[cmdSMID]; + bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), + ccb->cmd_dma_offset, ARC_IO_CMD_LEN, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + error = sc->pmuE[doneq_index].cmdFlag & ARC_RE_REPLY_QUEUE_ERR; + arc_scsi_cmd_done(sc, ccb, error); + doneq_index++; + if (doneq_index >= sc->doneq_entry) + doneq_index = 0; + sc->doneq_index = doneq_index; + arc_write(sc, ARC_RE_REPLY_CONSUMER_INDEX, doneq_index); + } + } + } + + return (ret); +} + + +int arc_intr(void *arg) { struct arc_softc *sc = arg; @@ -1104,12 +1436,18 @@ arc_intr(void *arg) case ARC_HBA_TYPE_A: ret = arc_intr_A(arg); break; + case ARC_HBA_TYPE_B: + ret = arc_intr_B(arg); + break; case ARC_HBA_TYPE_C: ret = arc_intr_C(arg); break; case ARC_HBA_TYPE_D: ret = arc_intr_D(arg); break; + case ARC_HBA_TYPE_E: + ret = arc_intr_E(arg); + break; } return (ret); } @@ -1123,10 +1461,6 @@ arc_scsi_cmd(struct scsi_xfer *xs) struct arc_msg_scsicmd *cmd; u_int32_t reg, cdb_len; int s; - struct arc_HBD_Msgu *pmu; - u_int16_t index_stripped; - u_int16_t postq_index; - struct InBound_SRB *pinbound_srb; if (xs->cmdlen > ARC_MSG_CDBLEN) { bzero(&xs->sense, sizeof(xs->sense)); @@ -1149,7 +1483,7 @@ arc_scsi_cmd(struct scsi_xfer *xs) cmd = &ccb->ccb_cmd->cmd; reg = ccb->ccb_cmd_post; - ccb->ccb_cmd->ccb = ccb; + ccb->ccb_cmd->ccb_id = ccb->ccb_id; /* bus is always 0 */ cmd->target = link->target; cmd->lun = link->lun; @@ -1170,7 +1504,7 @@ arc_scsi_cmd(struct scsi_xfer *xs) /* we've built the command, let's put it on the hw */ bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - ccb->cmd_dma_offset, ARC_MAX_IOCMDLEN, + ccb->cmd_dma_offset, ARC_IO_CMD_LEN, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); s = splbio(); @@ -1180,6 +1514,21 @@ arc_scsi_cmd(struct scsi_xfer *xs) reg |= ARC_RA_POST_QUEUE_BIGFRAME; arc_write(sc, ARC_RA_POST_QUEUE, reg); break; + case ARC_HBA_TYPE_B: { + struct arc_HBB_Msgu *pmuB = sc->pmuB; + u_int32_t ending_index, index = pmuB->postq_index; + + ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); + pmuB->post_qbuffer[ending_index] = 0; + if (cmd->flags & ARC_MSG_SCSICMD_FLAG_SGL_BSIZE_512) + reg |= ARC_RA_POST_QUEUE_BIGFRAME; + pmuB->post_qbuffer[index] = reg; + index++; + index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ + pmuB->postq_index = index; + arc_write(sc, sc->inb_doorbell, ARC_RB_D2I_CDB_POSTED); + break; + } case ARC_HBA_TYPE_C: cdb_len = sizeof(struct arc_msg_scsicmd) + sizeof(struct arc_sge) * ccb->ccb_dmamap->dm_nsegs; @@ -1190,31 +1539,48 @@ arc_scsi_cmd(struct scsi_xfer *xs) arc_write(sc, ARC_RC_INB_POSTQ_HIGH, sc->sc_ccb_phys_hi); arc_write(sc, ARC_RC_INB_POSTQ_LOW, reg); break; - case ARC_HBA_TYPE_D: - pmu = sc->pmu; - postq_index = pmu->postq_index; - pinbound_srb = (struct InBound_SRB *)&pmu->post_qbuffer[postq_index & 0xFF]; + case ARC_HBA_TYPE_D: { + struct arc_HBD_Msgu *pmu; + u_int16_t index_stripped; + u_int16_t postq_index; + struct InBound_SRB *pinbound_srb; + pmu = sc->pmu; + postq_index = pmu->postq_index; + pinbound_srb = (struct InBound_SRB *)&pmu->post_qbuffer[postq_index & 0xFF]; - pinbound_srb->addressHigh = sc->sc_ccb_phys_hi; - pinbound_srb->addressLow = ccb->ccb_cmd_post; - pinbound_srb->length = ccb->arc_io_cmd_length >> 2; - cmd->context = ccb->ccb_cmd_post; - if (postq_index & 0x4000) { - index_stripped = postq_index & 0xFF; - index_stripped += 1; - index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE; - pmu->postq_index = index_stripped ? (index_stripped | 0x4000) : index_stripped; - } else { - index_stripped = postq_index; - index_stripped += 1; - index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE; - pmu->postq_index = index_stripped ? index_stripped : (index_stripped | 0x4000); - } - bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - sc->cmdQ_ptr_offset, ARC_MAX_CMDQ_PTR_LEN, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - arc_write(sc, ARC_RD_INB_WRITE_PTR, postq_index); + pinbound_srb->addressHigh = sc->sc_ccb_phys_hi; + pinbound_srb->addressLow = ccb->ccb_cmd_post; + pinbound_srb->length = ccb->arc_io_cmd_length >> 2; + cmd->context = ccb->ccb_cmd_post; + if (postq_index & 0x4000) { + index_stripped = postq_index & 0xFF; + index_stripped += 1; + index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE; + pmu->postq_index = index_stripped ? (index_stripped | 0x4000) : index_stripped; + } else { + index_stripped = postq_index; + index_stripped += 1; + index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE; + pmu->postq_index = index_stripped ? index_stripped : (index_stripped | 0x4000); + } + bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), + sc->cmdQ_ptr_offset, ARC_HBD_CMDQ_PTR_LEN, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + arc_write(sc, ARC_RD_INB_WRITE_PTR, postq_index); break; + } + case ARC_HBA_TYPE_E: + cdb_len = sizeof(struct arc_msg_scsicmd) + + sizeof(struct arc_sge) * ccb->ccb_dmamap->dm_nsegs; + if (cdb_len > 0x300) + cdb_len = 0x300; + reg = ccb->smid | ((cdb_len - 1) >> 6); + bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), + sc->cmdQ_ptr_offset, ARC_HBE_COMPLETION_Q_LEN, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + arc_write(sc, ARC_RE_INB_POSTQ_HIGH, 0); + arc_write(sc, ARC_RE_INB_POSTQ_LOW, reg); + break; } if (xs->flags & SCSI_POLL) { if (arc_complete(sc, ccb, xs->timeout) != 0) { @@ -1334,7 +1700,6 @@ arc_complete(struct arc_softc *sc, struct arc_ccb *ncc struct arc_io_cmd *cmd; u_int32_t reg, error, write_ptr; u_int16_t doneq_index; - struct arc_HBD_Msgu *phbdmu; int ret = 0; arc_disable_all_intr(sc); @@ -1344,11 +1709,27 @@ arc_complete(struct arc_softc *sc, struct arc_ccb *ncc reg = arc_read(sc, ARC_RA_REPLY_QUEUE); error = (reg & ARC_RA_REPLY_QUEUE_ERR)? 1:0; break; + case ARC_HBA_TYPE_B: { + struct arc_HBB_Msgu *pmuB = sc->pmuB; + doneq_index = pmuB->doneq_index; + reg = pmuB->done_qbuffer[doneq_index]; + if ( reg == 0) { + reg = 0xffffffff; + break; + } + pmuB->done_qbuffer[doneq_index] = 0; + doneq_index++; + doneq_index %= ARCMSR_MAX_HBB_POSTQUEUE; + pmuB->doneq_index = doneq_index; + error = (reg & ARC_RB_REPLY_QUEUE_ERR)? 1:0; + break; + } case ARC_HBA_TYPE_C: reg = arc_read(sc, ARC_RC_OUTB_REPLYQ_LOW); error = (reg & ARC_RC_REPLY_QUEUE_ERR); break; - case ARC_HBA_TYPE_D: + case ARC_HBA_TYPE_D: { + struct arc_HBD_Msgu *phbdmu; phbdmu = sc->pmu; write_ptr = phbdmu->done_qbuffer[0].addressLow; doneq_index = phbdmu->doneq_index; @@ -1365,6 +1746,26 @@ Loop0: } error = (reg & ARC_RD_REPLY_QUEUE_ERR); break; + } + case ARC_HBA_TYPE_E: { + u_int16_t cmdSMID; + u_int16_t doneq_index; + doneq_index = sc->doneq_index; + if ((arc_read(sc, ARC_RE_REPLY_PRODUCER_INDEX) & 0xFFFF) == doneq_index) + reg = 0xffffffff; + else { + cmdSMID = sc->pmuE[doneq_index].cmdSMID; + ccb = &sc->sc_ccbs[cmdSMID]; + error = sc->pmuE[doneq_index].cmdFlag & ARC_RE_REPLY_QUEUE_ERR; + doneq_index++; + if (doneq_index >= sc->doneq_entry) + doneq_index = 0; + sc->doneq_index = doneq_index; + arc_write(sc, ARC_RE_REPLY_CONSUMER_INDEX, doneq_index); + reg = 0; + } + break; + } } if (reg == 0xffffffff) { if (timeout-- == 0) { @@ -1376,20 +1777,24 @@ Loop0: switch(sc->sc_adp_type) { case ARC_HBA_TYPE_A: + case ARC_HBA_TYPE_B: cmd = (struct arc_io_cmd *)(kva + ((reg << ARC_RA_REPLY_QUEUE_ADDR_SHIFT) - ARC_DMA_DVA(sc->sc_requests))); - break; + break; case ARC_HBA_TYPE_C: case ARC_HBA_TYPE_D: cmd = (struct arc_io_cmd *)(kva + ((reg & 0xFFFFFFE0) - - ARC_DMA_DVA(sc->sc_requests))); - break; + ARC_DMA_DVA(sc->sc_requests))); + break; + case ARC_HBA_TYPE_E: + cmd = ccb->ccb_cmd; + break; } - ccb = cmd->ccb; + ccb = &sc->sc_ccbs[cmd->ccb_id]; bus_dmamap_sync(sc->sc_dmat, ARC_DMA_MAP(sc->sc_requests), - ccb->cmd_dma_offset, ARC_MAX_IOCMDLEN, + ccb->cmd_dma_offset, ARC_IO_CMD_LEN, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); arc_scsi_cmd_done(sc, ccb, error); @@ -1411,6 +1816,10 @@ arc_enable_all_intr(struct arc_softc *sc) ARC_RA_INTRMASK_DOORBELL | ARC_RA_INTRMASK_MSG0); arc_write(sc, ARC_RA_INTRMASK, int_mask); break; + case ARC_HBA_TYPE_B: + int_mask = sc->sc_int_mask | ARC_RB_I2D_INTR_ENABLE_DOORBELL; + arc_write(sc, sc->outb_doorbell_mask, int_mask); + break; case ARC_HBA_TYPE_C: int_mask = arc_read(sc, ARC_RC_INTR_MASK); int_mask &= ~(ARC_RC_INTR_MASK_POSTQUEUE | @@ -1422,6 +1831,12 @@ arc_enable_all_intr(struct arc_softc *sc) int_mask |= ARC_RD_INTR_ENABLE_ALL; arc_write(sc, ARC_RD_INTR_ENABLE, int_mask); break; + case ARC_HBA_TYPE_E: + int_mask = arc_read(sc, ARC_RE_INTR_MASK); + int_mask &= ~(ARC_RE_INTR_MASK_POSTQUEUE | + ARC_RE_INTR_MASK_DOORBELL); + arc_write(sc, ARC_RE_INTR_MASK, int_mask); + break; } } @@ -1436,6 +1851,11 @@ arc_disable_all_intr(struct arc_softc *sc) int_mask |= ARC_RA_INTR_MASK_ALL; arc_write(sc, ARC_RA_INTRMASK, int_mask); break; + case ARC_HBA_TYPE_B: + int_mask = arc_read(sc, sc->outb_doorbell_mask); + arc_write(sc, sc->outb_doorbell_mask, 0); + sc->sc_int_mask = int_mask; + break; case ARC_HBA_TYPE_C: int_mask = arc_read(sc, ARC_RC_INTR_MASK); int_mask |= ARC_RC_INTR_MASK_ALL; @@ -1444,8 +1864,13 @@ arc_disable_all_intr(struct arc_softc *sc) case ARC_HBA_TYPE_D: int_mask = arc_read(sc, ARC_RD_INTR_ENABLE); int_mask &= ~ARC_RD_INTR_ENABLE_ALL; - arc_write(sc, ARC_RD_INTR_ENABLE, ARC_RD_INTR_DISABLE_ALL); + arc_write(sc, ARC_RD_INTR_ENABLE, int_mask); break; + case ARC_HBA_TYPE_E: + int_mask = arc_read(sc, ARC_RE_INTR_MASK); + int_mask |= ARC_RE_INTR_MASK_ALL; + arc_write(sc, ARC_RE_INTR_MASK, int_mask); + break; } } @@ -1463,16 +1888,33 @@ arc_map_pci_resources(struct arc_softc *sc, struct pci case ARC_HBA_TYPE_A: memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_RA_PCI_BAR); if (pci_mapreg_map(pa, ARC_RA_PCI_BAR, memtype, 0, &sc->sc_iot, - &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { + &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { printf(": unable to map ARC_HBA_TYPE_A system" " interface register\n"); return(1); } break; + case ARC_HBA_TYPE_B: + memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_RB_DOORBELL_BAR); + if (pci_mapreg_map(pa, ARC_RB_DOORBELL_BAR, memtype, 0, &sc->sc_iot, + &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { + printf(": unable to map ARC_HBA_TYPE_B system" + " interface register\n"); + return(1); + } + memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_RB_RWBUFFER_BAR); + if (pci_mapreg_map(pa, ARC_RB_RWBUFFER_BAR, memtype, 0, &sc->sc_msgt, + &sc->sc_msgh, NULL, &sc->sc_msgs, 0) != 0) { + printf(": unable to map ARC_HBA_TYPE_B buffer" + " interface register\n"); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); + return(1); + } + break; case ARC_HBA_TYPE_C: memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_RC_PCI_BAR); if (pci_mapreg_map(pa, ARC_RC_PCI_BAR, memtype, 0, &sc->sc_iot, - &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { + &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { printf(": unable to map ARC_HBA_TYPE_C system" " interface register\n"); return(1); @@ -1481,12 +1923,25 @@ arc_map_pci_resources(struct arc_softc *sc, struct pci case ARC_HBA_TYPE_D: memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_RD_PCI_BAR); if (pci_mapreg_map(pa, ARC_RD_PCI_BAR, memtype, 0, &sc->sc_iot, - &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { + &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { printf(": unable to map ARC_HBA_TYPE_D system" " interface register\n"); return(1); } break; + case ARC_HBA_TYPE_E: + memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, ARC_RE_PCI_BAR); + if (pci_mapreg_map(pa, ARC_RE_PCI_BAR, memtype, 0, &sc->sc_iot, + &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { + printf(": unable to map ARC_HBA_TYPE_E system" + " interface register\n"); + return(1); + } + arc_write(sc, ARC_RE_INTR_STAT, 0); + arc_write(sc, ARC_RE_OUTB_DOORBELL, ARC_RE_DOORBELL_SYNC); + sc->in_doorbell = 0; + sc->out_doorbell = 0; + break; } arc_disable_all_intr(sc); @@ -1506,8 +1961,7 @@ arc_map_pci_resources(struct arc_softc *sc, struct pci return (0); unmap: - bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); - sc->sc_ios = 0; + arc_unmap_pci_resources(sc); return (1); } @@ -1516,119 +1970,116 @@ arc_unmap_pci_resources(struct arc_softc *sc) { pci_intr_disestablish(sc->sc_pc, sc->sc_ih); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); + if (sc->sc_adp_type == ARC_HBA_TYPE_B) + bus_space_unmap(sc->sc_msgt, sc->sc_msgh, sc->sc_msgs); sc->sc_ios = 0; } -int -arc_chipA_firmware(struct arc_softc *sc) +void +arc_clear_doorbell_qbuffer(struct arc_softc *sc) { - struct arc_msg_firmware_info fwinfo; - char string[81]; /* sizeof(vendor)*2+1 */ - u_int32_t ob_doorbell; + u_int32_t ob_doorbell, i, tmp; - if (arc_wait_eq(sc, ARC_RA_OUTB_ADDR1, ARC_RA_OUTB_ADDR1_FIRMWARE_OK, - ARC_RA_OUTB_ADDR1_FIRMWARE_OK) != 0) { - printf("%s: timeout waiting for firmware ok\n", DEVNAME(sc)); - return (1); + switch(sc->sc_adp_type) { + case ARC_HBA_TYPE_A: + ob_doorbell = arc_read(sc, ARC_RA_OUTB_DOORBELL); + arc_write(sc, ARC_RA_OUTB_DOORBELL, ob_doorbell); + arc_write(sc, ARC_RA_INB_DOORBELL, ARC_RA_INB_DOORBELL_READ_OK); + for (i = 0; i < 200; i++) { + delay(20000); + ob_doorbell = arc_read(sc, ARC_RA_OUTB_DOORBELL); + if (ob_doorbell & ARC_RA_OUTB_DOORBELL_WRITE_OK) { + arc_write(sc, ARC_RA_OUTB_DOORBELL, ob_doorbell); + arc_write(sc, ARC_RA_INB_DOORBELL, + ARC_RA_INB_DOORBELL_READ_OK); + } else + break; + } + break; + case ARC_HBA_TYPE_B: + arc_write(sc, sc->outb_doorbell, ARC_RB_DOORBELL_INT_CLEAR_PATTERN); + arc_write(sc, sc->inb_doorbell, ARC_RB_D2I_DATA_READ_OK); + for (i = 0; i < 200; i++) { + delay(20000); + if (arc_read(sc, sc->outb_doorbell) & ARC_RB_I2D_DATA_WRITE_OK) { + arc_write(sc, sc->outb_doorbell, + ARC_RB_DOORBELL_INT_CLEAR_PATTERN); + arc_write(sc, sc->inb_doorbell, + ARC_RB_D2I_DATA_READ_OK); + } else + break; + } + break; + case ARC_HBA_TYPE_C: + ob_doorbell = arc_read(sc, ARC_RC_OUTB_DOORBELL); + arc_write(sc, ARC_RC_OUTB_DOORBELL_CLR, ob_doorbell); + arc_write(sc, ARC_RC_INB_DOORBELL, ARC_RC_D2I_DATA_READ_OK); + for (i = 0; i < 200; i++) { + delay(20000); + ob_doorbell = arc_read(sc, ARC_RC_OUTB_DOORBELL); + if (ob_doorbell & ARC_RC_I2D_DATA_WRITE_OK) { + arc_write(sc, ARC_RC_OUTB_DOORBELL_CLR, + ob_doorbell); + arc_write(sc, ARC_RC_INB_DOORBELL, + ARC_RC_D2I_DATA_READ_OK); + } else + break; + } + break; + case ARC_HBA_TYPE_D: + ob_doorbell = arc_read(sc, ARC_RD_OUTB_DOORBELL); + arc_write(sc, ARC_RD_OUTB_DOORBELL_CLR, ob_doorbell); + arc_write(sc, ARC_RD_INB_DOORBELL, ARC_RD_D2I_DATA_READ_OK); + for (i = 0; i < 200; i++) { + delay(20000); + ob_doorbell = arc_read(sc, ARC_RD_OUTB_DOORBELL); + if (ob_doorbell & ARC_RD_I2D_DATA_WRITE_OK) { + arc_write(sc, ARC_RD_OUTB_DOORBELL_CLR, + ob_doorbell); + arc_write(sc, ARC_RD_INB_DOORBELL, + ARC_RD_D2I_DATA_READ_OK); + } else + break; + } + break; + case ARC_HBA_TYPE_E: + sc->in_doorbell = arc_read(sc, ARC_RE_OUTB_DOORBELL); + arc_write(sc, ARC_RE_INTR_STAT, 0); + sc->out_doorbell ^= ARC_RE_D2I_DATA_READ_OK; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + for (i = 0; i < 200; i++) { + delay(20000); + tmp = sc->in_doorbell; + sc->in_doorbell = arc_read(sc, ARC_RE_OUTB_DOORBELL); + if ((tmp ^ sc->in_doorbell) & ARC_RE_I2D_DATA_WRITE_OK) { + arc_write(sc, ARC_RE_INTR_STAT, 0); + sc->out_doorbell ^= ARC_RE_D2I_DATA_READ_OK; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + } else + break; + } + break; } - - if (arc_msg0(sc, ARC_RA_INB_MSG0_GET_CONFIG) != 0) { - printf("%s: timeout waiting for get config\n", DEVNAME(sc)); - return (1); - } - - arc_read_region(sc, ARC_RA_MSGBUF, &fwinfo, sizeof(fwinfo)); - - DNPRINTF(ARC_D_INIT, "%s: signature: 0x%08x\n", DEVNAME(sc), - letoh32(fwinfo.signature)); - - if (letoh32(fwinfo.signature) != ARC_FWINFO_SIGNATURE_GET_CONFIG) { - printf("%s: invalid firmware info from iop\n", DEVNAME(sc)); - return (1); - } - - DNPRINTF(ARC_D_INIT, "%s: request_len: %d\n", DEVNAME(sc), - letoh32(fwinfo.request_len)); - DNPRINTF(ARC_D_INIT, "%s: queue_len: %d\n", DEVNAME(sc), - letoh32(fwinfo.queue_len)); - DNPRINTF(ARC_D_INIT, "%s: sdram_size: %d\n", DEVNAME(sc), - letoh32(fwinfo.sdram_size)); - DNPRINTF(ARC_D_INIT, "%s: sata_ports: %d\n", DEVNAME(sc), - letoh32(fwinfo.sata_ports), letoh32(fwinfo.sata_ports)); - - scsi_strvis(string, fwinfo.vendor, sizeof(fwinfo.vendor)); - DNPRINTF(ARC_D_INIT, "%s: vendor: \"%s\"\n", DEVNAME(sc), string); - scsi_strvis(string, fwinfo.model, sizeof(fwinfo.model)); - DNPRINTF(ARC_D_INIT, "%s: model: \"%s\"\n", DEVNAME(sc), string); - - scsi_strvis(string, fwinfo.fw_version, sizeof(fwinfo.fw_version)); - DNPRINTF(ARC_D_INIT, "%s: firmware: \"%s\"\n", DEVNAME(sc), string); - - if (letoh32(fwinfo.request_len) != ARC_MAX_IOCMDLEN) { - printf("%s: unexpected request frame size (%d != %d)\n", - DEVNAME(sc), letoh32(fwinfo.request_len), ARC_MAX_IOCMDLEN); - return (1); - } - - sc->sc_req_count = letoh32(fwinfo.queue_len); - - if (arc_msg0(sc, ARC_RA_INB_MSG0_START_BGRB) != 0) { - printf("%s: timeout waiting to start bg rebuild\n", - DEVNAME(sc)); - return (1); - } - - /* clear doorbell buffer */ - ob_doorbell = arc_read(sc, ARC_RA_OUTB_DOORBELL); - arc_write(sc, ARC_RA_OUTB_DOORBELL, ob_doorbell); - arc_write(sc, ARC_RA_INB_DOORBELL, ARC_RA_INB_DOORBELL_READ_OK); - - printf("%s: %d ports, %dMB SDRAM, firmware %s\n", - DEVNAME(sc), letoh32(fwinfo.sata_ports), - letoh32(fwinfo.sdram_size), string); - - return (0); } int -arc_chipB_firmware(struct arc_softc *sc) +arc_query_firmware(struct arc_softc *sc) { - if (arc_wait_eq(sc, ARC_RB_IOP2DRV_DOORBELL, - ARC_RA_OUTB_ADDR1_FIRMWARE_OK, - ARC_RA_OUTB_ADDR1_FIRMWARE_OK) != 0) { - printf("%s: timeout waiting for firmware ok\n", DEVNAME(sc)); - return (1); - } - - return (1); -} - -int -arc_chipC_firmware(struct arc_softc *sc) -{ struct arc_msg_firmware_info fwinfo; - char string[81]; /* sizeof(vendor)*2+1 */ - u_int32_t ob_doorbell; + char adapter_model[sizeof(fwinfo.model)+1]={0}; + char fw_version[sizeof(fwinfo.fw_version)+1]={0}; - if (arc_wait_eq(sc, ARC_RC_OUTB_MSGADDR1, ARC_RC_OUTB_MSG_FIRMWARE_OK, - ARC_RC_OUTB_MSG_FIRMWARE_OK) != 0) { - printf("%s: timeout waiting for firmware ok\n", DEVNAME(sc)); - return (1); - } - - if (arc_msg0(sc, ARC_RC_INB_MSG0_GET_CONFIG) != 0) { + if (arc_get_firmware_config(sc, &fwinfo)) { printf("%s: timeout waiting for get config\n", DEVNAME(sc)); - return (1); + return 1; } - arc_read_region(sc, ARC_RC_MSG_RWBUF, &fwinfo, sizeof(fwinfo)); - DNPRINTF(ARC_D_INIT, "%s: signature: 0x%08x\n", DEVNAME(sc), letoh32(fwinfo.signature)); if (letoh32(fwinfo.signature) != ARC_FWINFO_SIGNATURE_GET_CONFIG) { printf("%s: invalid firmware info from iop\n", DEVNAME(sc)); - return (1); + return 1; } DNPRINTF(ARC_D_INIT, "%s: request_len: %d\n", DEVNAME(sc), @@ -1638,114 +2089,83 @@ arc_chipC_firmware(struct arc_softc *sc) DNPRINTF(ARC_D_INIT, "%s: sdram_size: %d\n", DEVNAME(sc), letoh32(fwinfo.sdram_size)); DNPRINTF(ARC_D_INIT, "%s: sata_ports: %d\n", DEVNAME(sc), - letoh32(fwinfo.sata_ports), letoh32(fwinfo.sata_ports)); + letoh32(fwinfo.sata_ports)); - scsi_strvis(string, fwinfo.vendor, sizeof(fwinfo.vendor)); - DNPRINTF(ARC_D_INIT, "%s: vendor: \"%s\"\n", DEVNAME(sc), string); - scsi_strvis(string, fwinfo.model, sizeof(fwinfo.model)); - DNPRINTF(ARC_D_INIT, "%s: model: \"%s\"\n", DEVNAME(sc), string); + scsi_strvis(adapter_model, fwinfo.model, sizeof(fwinfo.model)); + scsi_strvis(fw_version, fwinfo.fw_version, sizeof(fwinfo.fw_version)); - scsi_strvis(string, fwinfo.fw_version, sizeof(fwinfo.fw_version)); - DNPRINTF(ARC_D_INIT, "%s: firmware: \"%s\"\n", DEVNAME(sc), string); - if (letoh32(fwinfo.request_len) != ARC_MAX_IOCMDLEN) { printf("%s: unexpected request frame size (%d != %d)\n", DEVNAME(sc), letoh32(fwinfo.request_len), ARC_MAX_IOCMDLEN); - return (1); + return 1; } sc->sc_req_count = letoh32(fwinfo.queue_len); - if (arc_msg0(sc, ARC_RC_INB_MSG0_START_BGRB) != 0) { - printf("%s: timeout waiting to start bg rebuild\n", - DEVNAME(sc)); - return (1); - } + printf("%s: %s, %s, F/W: %s\n", DEVNAME(sc), ARC_VERSION, + adapter_model, fw_version); - /* clear doorbell buffer */ - ob_doorbell = arc_read(sc, ARC_RC_OUTB_DOORBELL); - arc_write(sc, ARC_RC_OUTB_DOORBELL_CLR, ob_doorbell); - arc_write(sc, ARC_RC_INB_DOORBELL, ARC_RC_D2I_DATA_READ_OK); - - printf("%s: %d ports, %dMB SDRAM, firmware %s\n", - DEVNAME(sc), letoh32(fwinfo.sata_ports), - letoh32(fwinfo.sdram_size), string); - - return (0); + return 0; } int -arc_chipD_firmware(struct arc_softc *sc) +arc_get_firmware_config(struct arc_softc *sc, struct arc_msg_firmware_info *fwinfo) { - struct arc_msg_firmware_info fwinfo; - char string[81]; /* sizeof(vendor)*2+1 */ - u_int32_t ob_doorbell; + int ready = 1; - if (arc_wait_eq(sc, ARC_RD_OUTB_MSGADDR1, ARC_RD_OUTB_MSG_FIRMWARE_OK, - ARC_RD_OUTB_MSG_FIRMWARE_OK) != 0) { - printf("%s: timeout waiting for firmware ok\n", DEVNAME(sc)); - return (1); + switch(sc->sc_adp_type) { + case ARC_HBA_TYPE_A: + ready = arc_msg0(sc, ARC_RA_INB_MSG0_GET_CONFIG); + if (!ready) + arc_read_region(sc, ARC_RA_MSGBUF, fwinfo, sizeof(*fwinfo)); + break; + case ARC_HBA_TYPE_B: + ready = arc_msg0(sc, ARC_RB_INB_MSG0_GET_CONFIG); + if (!ready) + arc_read_region2(sc, ARC_RB_MSG_RWBUF, fwinfo, sizeof(*fwinfo)); + break; + case ARC_HBA_TYPE_C: + ready = arc_msg0(sc, ARC_RC_INB_MSG0_GET_CONFIG); + if (!ready) + arc_read_region(sc, ARC_RC_MSG_RWBUF, fwinfo, sizeof(*fwinfo)); + break; + case ARC_HBA_TYPE_D: + ready = arc_msg0(sc, ARC_RD_INB_MSG0_GET_CONFIG); + if (!ready) + arc_read_region(sc, ARC_RD_MSG_RWBUF, fwinfo, sizeof(*fwinfo)); + break; + case ARC_HBA_TYPE_E: + ready = arc_msg0(sc, ARC_RE_INB_MSG0_GET_CONFIG); + if (!ready) + arc_read_region(sc, ARC_RE_MSG_RWBUF, fwinfo, sizeof(*fwinfo)); + break; } + return ready; +} - if ((arc_read(sc, ARC_RD_OUTB_DOORBELL) & ARC_RD_I2D_MESSAGE_CMD_DONE)) - arc_write(sc, ARC_RD_OUTB_DOORBELL, ARC_RD_I2D_MESSAGE_CMD_DONE_CLEAR); +int +arc_start_bkgrnd_rebuild(struct arc_softc *sc) +{ + int ready = 1; - if (arc_msg0(sc, ARC_RD_INB_MSG0_GET_CONFIG) != 0) { - printf("%s: timeout waiting for get config\n", DEVNAME(sc)); - return (1); + switch(sc->sc_adp_type) { + case ARC_HBA_TYPE_A: + ready = arc_msg0(sc, ARC_RA_INB_MSG0_START_BGRB); + break; + case ARC_HBA_TYPE_B: + ready = arc_msg0(sc, ARC_RB_INB_MSG0_START_BGRB); + break; + case ARC_HBA_TYPE_C: + ready = arc_msg0(sc, ARC_RC_INB_MSG0_START_BGRB); + break; + case ARC_HBA_TYPE_D: + ready = arc_msg0(sc, ARC_RD_INB_MSG0_START_BGRB); + break; + case ARC_HBA_TYPE_E: + ready = arc_msg0(sc, ARC_RE_INB_MSG0_START_BGRB); + break; } - - arc_read_region(sc, ARC_RD_MSG_RWBUF, &fwinfo, sizeof(fwinfo)); - - DNPRINTF(ARC_D_INIT, "%s: signature: 0x%08x\n", DEVNAME(sc), - letoh32(fwinfo.signature)); - - if (letoh32(fwinfo.signature) != ARC_FWINFO_SIGNATURE_GET_CONFIG) { - printf("%s: invalid firmware info from iop\n", DEVNAME(sc)); - return (1); - } - - DNPRINTF(ARC_D_INIT, "%s: request_len: %d\n", DEVNAME(sc), - letoh32(fwinfo.request_len)); - DNPRINTF(ARC_D_INIT, "%s: queue_len: %d\n", DEVNAME(sc), - letoh32(fwinfo.queue_len)); - DNPRINTF(ARC_D_INIT, "%s: sdram_size: %d\n", DEVNAME(sc), - letoh32(fwinfo.sdram_size)); - DNPRINTF(ARC_D_INIT, "%s: sata_ports: %d\n", DEVNAME(sc), - letoh32(fwinfo.sata_ports), letoh32(fwinfo.sata_ports)); - - scsi_strvis(string, fwinfo.vendor, sizeof(fwinfo.vendor)); - DNPRINTF(ARC_D_INIT, "%s: vendor: \"%s\"\n", DEVNAME(sc), string); - scsi_strvis(string, fwinfo.model, sizeof(fwinfo.model)); - DNPRINTF(ARC_D_INIT, "%s: model: \"%s\"\n", DEVNAME(sc), string); - - scsi_strvis(string, fwinfo.fw_version, sizeof(fwinfo.fw_version)); - DNPRINTF(ARC_D_INIT, "%s: firmware: \"%s\"\n", DEVNAME(sc), string); - - if (letoh32(fwinfo.request_len) != ARC_MAX_IOCMDLEN) { - printf("%s: unexpected request frame size (%d != %d)\n", - DEVNAME(sc), letoh32(fwinfo.request_len), ARC_MAX_IOCMDLEN); - return (1); - } - - sc->sc_req_count = letoh32(fwinfo.queue_len) - 1; - - if (arc_msg0(sc, ARC_RD_INB_MSG0_START_BGRB) != 0) { - printf("%s: timeout waiting to start bg rebuild\n", - DEVNAME(sc)); - return (1); - } - - /* clear doorbell buffer */ - ob_doorbell = arc_read(sc, ARC_RD_OUTB_DOORBELL); - arc_write(sc, ARC_RD_OUTB_DOORBELL_CLR, ob_doorbell); - arc_write(sc, ARC_RD_INB_DOORBELL, ARC_RD_D2I_DATA_READ_OK); - - printf("%s: %d ports, %dMB SDRAM, firmware %s\n", - DEVNAME(sc), letoh32(fwinfo.sata_ports), - letoh32(fwinfo.sdram_size), string); - - return (0); + return ready; } void @@ -1757,6 +2177,11 @@ arc_stop_bgrb_proc(struct arc_softc *sc) printf("%s: timeout waiting to stop bg rebuild\n", DEVNAME(sc)); break; + case ARC_HBA_TYPE_B: + if (arc_msg0(sc, ARC_RB_INB_MSG0_STOP_BGRB) != 0) + printf("%s: timeout waiting to stop bg rebuild\n", + DEVNAME(sc)); + break; case ARC_HBA_TYPE_C: if (arc_msg0(sc, ARC_RC_INB_MSG0_STOP_BGRB) != 0) printf("%s: timeout waiting to stop bg rebuild\n", @@ -1767,6 +2192,11 @@ arc_stop_bgrb_proc(struct arc_softc *sc) printf("%s: timeout waiting to stop bg rebuild\n", DEVNAME(sc)); break; + case ARC_HBA_TYPE_E: + if (arc_msg0(sc, ARC_RE_INB_MSG0_STOP_BGRB) != 0) + printf("%s: timeout waiting to stop bg rebuild\n", + DEVNAME(sc)); + break; } } @@ -1779,6 +2209,11 @@ arc_flush_cache(struct arc_softc *sc) printf("%s: timeout waiting to flush cache\n", DEVNAME(sc)); break; + case ARC_HBA_TYPE_B: + if (arc_msg0(sc, ARC_RB_INB_MSG0_FLUSH_CACHE) != 0) + printf("%s: timeout waiting to flush cache\n", + DEVNAME(sc)); + break; case ARC_HBA_TYPE_C: if (arc_msg0(sc, ARC_RC_INB_MSG0_FLUSH_CACHE) != 0) printf("%s: timeout waiting to flush cache\n", @@ -1789,6 +2224,11 @@ arc_flush_cache(struct arc_softc *sc) printf("%s: timeout waiting to flush cache\n", DEVNAME(sc)); break; + case ARC_HBA_TYPE_E: + if (arc_msg0(sc, ARC_RE_INB_MSG0_FLUSH_CACHE) != 0) + printf("%s: timeout waiting to flush cache\n", + DEVNAME(sc)); + break; } } @@ -1802,12 +2242,26 @@ arc_iop_set_conf(struct arc_softc *sc) switch (sc->sc_adp_type) { case ARC_HBA_TYPE_A: arc_write(sc, ARC_RA_MSGBUF, ARC_FWINFO_SIGNATURE_SET_CONFIG); - arc_write(sc, ARC_RA_MSGBUF+1, ccb_phys_hi); + arc_write(sc, ARC_RA_MSGBUF+4, ccb_phys_hi); arc_msg0(sc, ARC_RA_INB_MSG0_SET_CONFIG); break; + case ARC_HBA_TYPE_B: { + struct arc_HBB_Msgu *pmuB = sc->pmuB; + pmuB->postq_index = 0; + pmuB->doneq_index = 0; + arc_msg0(sc, ARC_RB_INB_MSG0_SET_POST_WINDOW); + arc_write2(sc, ARC_RB_MSG_RWBUF, ARC_FWINFO_SIGNATURE_SET_CONFIG); + arc_write2(sc, ARC_RB_MSG_RWBUF+4, ccb_phys_hi); + arc_write2(sc, ARC_RB_MSG_RWBUF+8, sc->postQ_buffer); + arc_write2(sc, ARC_RB_MSG_RWBUF+12, sc->doneQ_buffer); + arc_write2(sc, ARC_RB_MSG_RWBUF+16, 1056); + arc_msg0(sc, ARC_RB_INB_MSG0_SET_CONFIG); + arc_msg0(sc, ARC_RB_INB_MSG0_START_DRIVER_MODE); + break; + } case ARC_HBA_TYPE_C: arc_write(sc, ARC_RC_MSG_RWBUF, ARC_FWINFO_SIGNATURE_SET_CONFIG); - arc_write(sc, ARC_RC_MSG_RWBUF+1, ccb_phys_hi); + arc_write(sc, ARC_RC_MSG_RWBUF+4, ccb_phys_hi); arc_msg0(sc, ARC_RC_INB_MSG0_SET_CONFIG); break; case ARC_HBA_TYPE_D: @@ -1821,6 +2275,17 @@ arc_iop_set_conf(struct arc_softc *sc) arc_write(sc, ARC_RD_MSG_RWBUF+16, 0x100); arc_msg0(sc, ARC_RD_INB_MSG0_SET_CONFIG); break; + case ARC_HBA_TYPE_E: + arc_write(sc, ARC_RC_MSG_RWBUF, ARC_FWINFO_SIGNATURE_SET_CONFIG); + arc_write(sc, ARC_RC_MSG_RWBUF+4, ARC_SIGNATURE_1884); + arc_write(sc, ARC_RC_MSG_RWBUF+8, sc->sc_ccb_phys_lo); + arc_write(sc, ARC_RC_MSG_RWBUF+12, sc->sc_ccb_phys_hi); + arc_write(sc, ARC_RC_MSG_RWBUF+16, ARC_IO_CMD_LEN); + arc_write(sc, ARC_RC_MSG_RWBUF+20, sc->doneq_phys_lo); + arc_write(sc, ARC_RC_MSG_RWBUF+24, sc->doneq_phys_hi); + arc_write(sc, ARC_RC_MSG_RWBUF+28, ARC_HBE_COMPLETION_Q_LEN); + arc_msg0(sc, ARC_RE_INB_MSG0_SET_CONFIG); + break; } } @@ -2287,12 +2752,18 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb case ARC_HBA_TYPE_A: reg = arc_read(sc, ARC_RA_OUTB_DOORBELL); break; + case ARC_HBA_TYPE_B: + reg = arc_read(sc, sc->outb_doorbell); + break; case ARC_HBA_TYPE_C: reg = arc_read(sc, ARC_RC_OUTB_DOORBELL); break; case ARC_HBA_TYPE_D: reg = arc_read(sc, ARC_RD_OUTB_DOORBELL); break; + case ARC_HBA_TYPE_E: + reg = arc_read(sc, ARC_RE_OUTB_DOORBELL); + break; } /* if (reg) return (EBUSY); */ @@ -2334,17 +2805,27 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb /* copy the chunk to the hw */ arc_write(sc, ARC_RA_IOC_WBUF_LEN, rwlen); arc_write_region(sc, ARC_RA_IOC_WBUF, rwbuf, - sizeof(rwbuf)); + sizeof(rwbuf)); /* say we have a buffer for the hw */ arc_write(sc, ARC_RA_INB_DOORBELL, ARC_RA_INB_DOORBELL_WRITE_OK); break; + case ARC_HBA_TYPE_B: + /* copy the chunk to the hw */ + arc_write2(sc, ARC_RB_MSG_WBUF, rwlen); + arc_write_region2(sc, ARC_RB_MSG_WBUF+4, rwbuf, + sizeof(rwbuf)); + + /* say we have a buffer for the hw */ + arc_write(sc, sc->inb_doorbell, + ARC_RB_D2I_DATA_WRITE_OK); + break; case ARC_HBA_TYPE_C: /* copy the chunk to the hw */ arc_write(sc, ARC_RC_MSG_WBUF_LEN, rwlen); arc_write_region(sc, ARC_RC_MSG_WBUF, rwbuf, - sizeof(rwbuf)); + sizeof(rwbuf)); /* say we have a buffer for the hw */ arc_write(sc, ARC_RC_INB_DOORBELL, @@ -2354,12 +2835,22 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb /* copy the chunk to the hw */ arc_write(sc, ARC_RD_MSG_WBUF_LEN, rwlen); arc_write_region(sc, ARC_RD_MSG_WBUF, rwbuf, - sizeof(rwbuf)); + sizeof(rwbuf)); /* say we have a buffer for the hw */ arc_write(sc, ARC_RD_INB_DOORBELL, ARC_RD_D2I_DATA_WRITE_OK); break; + case ARC_HBA_TYPE_E: + /* copy the chunk to the hw */ + arc_write(sc, ARC_RE_MSG_WBUF_LEN, rwlen); + arc_write_region(sc, ARC_RE_MSG_WBUF, rwbuf, + sizeof(rwbuf)); + + /* say we have a buffer for the hw */ + sc->out_doorbell ^= ARC_RE_D2I_DATA_WRITE_OK; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + break; } wdone += rwlen; } @@ -2375,6 +2866,13 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb write_ok = reg & ARC_RA_OUTB_DOORBELL_WRITE_OK; read_ok = reg & ARC_RA_OUTB_DOORBELL_READ_OK; break; + case ARC_HBA_TYPE_B: + while ((reg = arc_read(sc, sc->outb_doorbell)) == 0) + arc_wait(sc); + arc_write(sc, sc->outb_doorbell, ~(reg & ARC_RB_I2D_DOORBELL_INT)); + write_ok = reg & ARC_RB_I2D_DATA_WRITE_OK; + read_ok = reg & ARC_RB_I2D_DATA_READ_OK; + break; case ARC_HBA_TYPE_C: while ((reg = arc_read(sc, ARC_RC_OUTB_DOORBELL)) == 0) arc_wait(sc); @@ -2389,6 +2887,20 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb write_ok = reg & ARC_RD_I2D_DATA_WRITE_OK; read_ok = reg & ARC_RD_I2D_DATA_READ_OK; break; + case ARC_HBA_TYPE_E: { + u_int32_t val; + do { + arc_wait(sc); + reg = arc_read(sc, ARC_RE_OUTB_DOORBELL); + } while ((reg ^ sc->in_doorbell) == 0); + val = reg ^ sc->in_doorbell; + sc->in_doorbell = reg; + reg = val; + arc_write(sc, ARC_RE_INTR_STAT, 0); + write_ok = reg & ARC_RE_I2D_DATA_WRITE_OK; + read_ok = reg & ARC_RE_I2D_DATA_READ_OK; + break; + } } DNPRINTF(ARC_D_DB, "%s: reg: 0x%08x\n", DEVNAME(sc), reg); @@ -2397,12 +2909,18 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb case ARC_HBA_TYPE_A: rwlen = arc_read(sc, ARC_RA_IOC_RBUF_LEN); break; + case ARC_HBA_TYPE_B: + rwlen = arc_read2(sc, ARC_RB_MSG_RBUF); + break; case ARC_HBA_TYPE_C: rwlen = arc_read(sc, ARC_RC_MSG_RBUF_LEN); break; case ARC_HBA_TYPE_D: rwlen = arc_read(sc, ARC_RD_MSG_RBUF_LEN); break; + case ARC_HBA_TYPE_E: + rwlen = arc_read(sc, ARC_RE_MSG_RBUF_LEN); + break; } if (rwlen > sizeof(rwbuf)) { DNPRINTF(ARC_D_DB, "%s: rwlen too big\n", @@ -2414,22 +2932,34 @@ arc_msgbuf(struct arc_softc *sc, void *wptr, size_t wb switch(sc->sc_adp_type) { case ARC_HBA_TYPE_A: arc_read_region(sc, ARC_RA_IOC_RBUF, rwbuf, - sizeof(rwbuf)); + sizeof(rwbuf)); arc_write(sc, ARC_RA_INB_DOORBELL, ARC_RA_INB_DOORBELL_READ_OK); break; + case ARC_HBA_TYPE_B: + arc_read_region2(sc, ARC_RB_MSG_RBUF+4, rwbuf, + sizeof(rwbuf)); + arc_write(sc, sc->inb_doorbell, + ARC_RB_I2D_DATA_READ_OK); + break; case ARC_HBA_TYPE_C: arc_read_region(sc, ARC_RC_MSG_RBUF, rwbuf, - sizeof(rwbuf)); + sizeof(rwbuf)); arc_write(sc, ARC_RC_INB_DOORBELL, ARC_RC_I2D_DATA_READ_OK); break; case ARC_HBA_TYPE_D: arc_read_region(sc, ARC_RD_MSG_RBUF, rwbuf, - sizeof(rwbuf)); + sizeof(rwbuf)); arc_write(sc, ARC_RD_INB_DOORBELL, ARC_RD_I2D_DATA_READ_OK); break; + case ARC_HBA_TYPE_E: + arc_read_region(sc, ARC_RE_MSG_RBUF, rwbuf, + sizeof(rwbuf)); + sc->out_doorbell ^= ARC_RE_I2D_DATA_READ_OK; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + break; } if ((rlen > 3) && (rdone == 3)) { rlen = *(u_int16_t *)rwbuf; @@ -2507,7 +3037,7 @@ out: void arc_lock(struct arc_softc *sc) { - int s; + int s; u_int32_t int_mask; rw_enter_write(&sc->sc_lock); @@ -2517,6 +3047,10 @@ arc_lock(struct arc_softc *sc) int_mask = arc_read(sc, ARC_RA_INTRMASK) | ARC_RA_INTRMASK_DOORBELL; arc_write(sc, ARC_RA_INTRMASK, int_mask); break; + case ARC_HBA_TYPE_B: + int_mask = arc_read(sc, sc->outb_doorbell_mask) & ~ARC_RB_I2D_INTR_ENABLE_DOORBELL; + arc_write(sc, sc->outb_doorbell_mask, int_mask); + break; case ARC_HBA_TYPE_C: int_mask = arc_read(sc, ARC_RC_INTR_MASK) | ARC_RC_INTR_MASK_DOORBELL; arc_write(sc, ARC_RC_INTR_MASK, int_mask); @@ -2525,6 +3059,10 @@ arc_lock(struct arc_softc *sc) int_mask = arc_read(sc, ARC_RD_INTR_ENABLE) & ~ARC_RD_INTR_ENABLE_DOORBELL; arc_write(sc, ARC_RD_INTR_ENABLE, int_mask); break; + case ARC_HBA_TYPE_E: + int_mask = arc_read(sc, ARC_RE_INTR_MASK) | ARC_RE_INTR_MASK_DOORBELL; + arc_write(sc, ARC_RE_INTR_MASK, int_mask); + break; } sc->sc_talking = 1; splx(s); @@ -2533,7 +3071,7 @@ arc_lock(struct arc_softc *sc) void arc_unlock(struct arc_softc *sc) { - int s; + int s; u_int32_t int_mask; s = splbio(); @@ -2543,6 +3081,10 @@ arc_unlock(struct arc_softc *sc) int_mask = arc_read(sc, ARC_RA_INTRMASK) & ~ARC_RA_INTRMASK_DOORBELL; arc_write(sc, ARC_RA_INTRMASK, int_mask); break; + case ARC_HBA_TYPE_B: + int_mask = arc_read(sc, sc->outb_doorbell_mask) | ARC_RB_I2D_INTR_ENABLE_DOORBELL; + arc_write(sc, sc->outb_doorbell_mask, int_mask); + break; case ARC_HBA_TYPE_C: int_mask = arc_read(sc, ARC_RC_INTR_MASK) & ~ARC_RC_INTR_MASK_DOORBELL; arc_write(sc, ARC_RC_INTR_MASK, int_mask); @@ -2551,6 +3093,10 @@ arc_unlock(struct arc_softc *sc) int_mask = arc_read(sc, ARC_RD_INTR_ENABLE) | ARC_RD_INTR_ENABLE_DOORBELL; arc_write(sc, ARC_RD_INTR_ENABLE, int_mask); break; + case ARC_HBA_TYPE_E: + int_mask = arc_read(sc, ARC_RE_INTR_MASK) & ~ARC_RE_INTR_MASK_DOORBELL; + arc_write(sc, ARC_RE_INTR_MASK, int_mask); + break; } splx(s); rw_exit_write(&sc->sc_lock); @@ -2559,7 +3105,7 @@ arc_unlock(struct arc_softc *sc) void arc_wait(struct arc_softc *sc) { - int error, s; + int error, s; u_int32_t int_mask; s = splbio(); @@ -2567,16 +3113,25 @@ arc_wait(struct arc_softc *sc) case ARC_HBA_TYPE_A: int_mask = arc_read(sc, ARC_RA_INTRMASK) & ~ARC_RA_INTRMASK_DOORBELL; arc_write(sc, ARC_RA_INTRMASK, int_mask); - error = tsleep_nsec(sc, PWAIT, "arcdb", SEC_TO_NSEC(1)); + error = tsleep(sc, PWAIT, "arcdb", hz); if (error == EWOULDBLOCK) { int_mask = arc_read(sc, ARC_RA_INTRMASK) | ARC_RA_INTRMASK_DOORBELL; arc_write(sc, ARC_RA_INTRMASK, int_mask); } break; + case ARC_HBA_TYPE_B: + int_mask = arc_read(sc, sc->outb_doorbell_mask) | ARC_RB_I2D_INTR_ENABLE_DOORBELL; + arc_write(sc, sc->outb_doorbell_mask, int_mask); + error = tsleep(sc, PWAIT, "arcdb", hz); + if (error == EWOULDBLOCK) { + int_mask = arc_read(sc, sc->outb_doorbell_mask) & ~ARC_RB_I2D_INTR_ENABLE_DOORBELL; + arc_write(sc, sc->outb_doorbell_mask, int_mask); + } + break; case ARC_HBA_TYPE_C: int_mask = arc_read(sc, ARC_RC_INTR_MASK) & ~ARC_RC_INTR_MASK_DOORBELL; arc_write(sc, ARC_RC_INTR_MASK, int_mask); - error = tsleep_nsec(sc, PWAIT, "arcdb", SEC_TO_NSEC(1)); + error = tsleep(sc, PWAIT, "arcdb", hz); if (error == EWOULDBLOCK) { int_mask = arc_read(sc, ARC_RC_INTR_MASK) | ARC_RC_INTR_MASK_DOORBELL; arc_write(sc, ARC_RC_INTR_MASK, int_mask); @@ -2585,12 +3140,21 @@ arc_wait(struct arc_softc *sc) case ARC_HBA_TYPE_D: int_mask = arc_read(sc, ARC_RD_INTR_ENABLE) | ARC_RD_INTR_ENABLE_DOORBELL; arc_write(sc, ARC_RD_INTR_ENABLE, int_mask); - error = tsleep_nsec(sc, PWAIT, "arcdb", SEC_TO_NSEC(1)); + error = tsleep(sc, PWAIT, "arcdb", hz); if (error == EWOULDBLOCK) { int_mask = arc_read(sc, ARC_RD_INTR_ENABLE) & ~ARC_RD_INTR_ENABLE_DOORBELL; arc_write(sc, ARC_RD_INTR_ENABLE, int_mask); } break; + case ARC_HBA_TYPE_E: + int_mask = arc_read(sc, ARC_RE_INTR_MASK) & ~ARC_RE_INTR_MASK_DOORBELL; + arc_write(sc, ARC_RE_INTR_MASK, int_mask); + error = tsleep(sc, PWAIT, "arcdb", hz); + if (error == EWOULDBLOCK) { + int_mask = arc_read(sc, ARC_RE_INTR_MASK) | ARC_RE_INTR_MASK_DOORBELL; + arc_write(sc, ARC_RE_INTR_MASK, int_mask); + } + break; } splx(s); } @@ -2612,7 +3176,7 @@ arc_create_sensors(void *xat) * XXX * this is bollocks. the firmware has garbage coming out of it * so we have to wait a bit for it to finish spewing. */ - tsleep_nsec(sc, PWAIT, "arcspew", SEC_TO_NSEC(2)); + tsleep(sc, PWAIT, "arcspew", hz * 2); bzero(&bi, sizeof(bi)); if (arc_bio_inq(sc, &bi) != 0) { @@ -2706,7 +3270,7 @@ arc_refresh_sensors(void *arg) u_int32_t arc_read(struct arc_softc *sc, bus_size_t r) { - u_int32_t v; + u_int32_t v; bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, BUS_SPACE_BARRIER_READ); @@ -2747,12 +3311,12 @@ int arc_wait_eq(struct arc_softc *sc, bus_size_t r, u_int32_t mask, u_int32_t target) { - int i; + int i; - DNPRINTF(ARC_D_RW, "%s: arc_wait_eq 0x%x 0x%08x 0x%08x\n", + DNPRINTF(ARC_D_RW, "%s: arc_wait_eq 0x%lx 0x%08x 0x%08x\n", DEVNAME(sc), r, mask, target); - for (i = 0; i < 10000; i++) { + for (i = 0; i < 60000; i++) { if ((arc_read(sc, r) & mask) == target) return (0); delay(1000); @@ -2762,10 +3326,31 @@ arc_wait_eq(struct arc_softc *sc, bus_size_t r, u_int3 } int +arc_wait_doorbell(struct arc_softc *sc, bus_size_t r, u_int32_t mask) +{ + int i; + u_int32_t doorbell; + + DNPRINTF(ARC_D_RW, "%s: arc_wait_doorbell 0x%x 0x%08x\n", + DEVNAME(sc), r, mask); + + for (i = 0; i < 10000; i++) { + doorbell = arc_read(sc, r); + if ((sc->in_doorbell ^ doorbell) & mask) { + sc->in_doorbell = doorbell; + return (0); + } + delay(1000); + } + + return (1); +} + +int arc_wait_ne(struct arc_softc *sc, bus_size_t r, u_int32_t mask, u_int32_t target) { - int i; + int i; DNPRINTF(ARC_D_RW, "%s: arc_wait_ne 0x%x 0x%08x 0x%08x\n", DEVNAME(sc), r, mask, target); @@ -2779,6 +3364,43 @@ arc_wait_ne(struct arc_softc *sc, bus_size_t r, u_int3 return (1); } +u_int32_t +arc_read2(struct arc_softc *sc, bus_size_t r) +{ + u_int32_t v; + + bus_space_barrier(sc->sc_msgt, sc->sc_msgh, r, 4, + BUS_SPACE_BARRIER_READ); + v = bus_space_read_4(sc->sc_msgt, sc->sc_msgh, r); + return (v); +} + +void +arc_write2(struct arc_softc *sc, bus_size_t r, u_int32_t v) +{ + DNPRINTF(ARC_D_RW, "%s: arc_write 0x%x 0x%08x\n", DEVNAME(sc), r, v); + + bus_space_write_4(sc->sc_msgt, sc->sc_msgh, r, v); + bus_space_barrier(sc->sc_msgt, sc->sc_msgh, r, 4, + BUS_SPACE_BARRIER_WRITE); +} + +void +arc_read_region2(struct arc_softc *sc, bus_size_t r, void *buf, size_t len) +{ + bus_space_barrier(sc->sc_msgt, sc->sc_msgh, r, len, + BUS_SPACE_BARRIER_READ); + bus_space_read_raw_region_4(sc->sc_msgt, sc->sc_msgh, r, buf, len); +} + +void +arc_write_region2(struct arc_softc *sc, bus_size_t r, void *buf, size_t len) +{ + bus_space_write_raw_region_4(sc->sc_msgt, sc->sc_msgh, r, buf, len); + bus_space_barrier(sc->sc_msgt, sc->sc_msgh, r, len, + BUS_SPACE_BARRIER_WRITE); +} + int arc_msg0(struct arc_softc *sc, u_int32_t m) { @@ -2788,20 +3410,33 @@ arc_msg0(struct arc_softc *sc, u_int32_t m) arc_write(sc, ARC_RA_INB_MSG0, m); /* wait for the fw to do it */ if (arc_wait_eq(sc, ARC_RA_INTRSTAT, ARC_RA_INTRSTAT_MSG0, - ARC_RA_INTRSTAT_MSG0) != 0) + ARC_RA_INTRSTAT_MSG0) != 0) return (1); /* ack it */ arc_write(sc, ARC_RA_INTRSTAT, ARC_RA_INTRSTAT_MSG0); break; + case ARC_HBA_TYPE_B: + /* post message */ + arc_write(sc, sc->inb_doorbell, m); + /* wait for the fw to do it */ + if (arc_wait_eq(sc, sc->outb_doorbell, ARC_RB_I2D_MSG_CMD_DONE, + ARC_RB_I2D_MSG_CMD_DONE) != 0) + return (1); + + /* ack it */ + arc_write(sc, sc->outb_doorbell, ARC_RB_MESSAGE_INT_CLEAR_PATTERN); + arc_write(sc, sc->inb_doorbell, ARC_RB_D2I_END_OF_INTERRUPT); + break; + case ARC_HBA_TYPE_C: /* post message */ arc_write(sc, ARC_RC_INB_MSGADDR0, m); arc_write(sc, ARC_RC_INB_DOORBELL, ARC_RC_D2I_MSG_CMD_DONE); /* wait for the fw to do it */ if (arc_wait_eq(sc, ARC_RC_OUTB_DOORBELL, ARC_RC_I2D_MSG_CMD_DONE, - ARC_RC_I2D_MSG_CMD_DONE) != 0) + ARC_RC_I2D_MSG_CMD_DONE) != 0) return (1); /* ack it */ @@ -2813,12 +3448,25 @@ arc_msg0(struct arc_softc *sc, u_int32_t m) arc_write(sc, ARC_RD_INB_MSGADDR0, m); /* wait for the fw to do it */ if (arc_wait_eq(sc, ARC_RD_OUTB_DOORBELL, ARC_RD_I2D_MSG_CMD_DONE, - ARC_RD_I2D_MSG_CMD_DONE) != 0) + ARC_RD_I2D_MSG_CMD_DONE) != 0) return (1); /* ack it */ arc_write(sc, ARC_RD_OUTB_DOORBELL_CLR, ARC_RD_I2D_MSG_CMD_DONE_CLR); break; + + case ARC_HBA_TYPE_E: + /* post message */ + arc_write(sc, ARC_RE_INB_MSGADDR0, m); + sc->out_doorbell ^= ARC_RE_D2I_MSG_CMD_DONE; + arc_write(sc, ARC_RE_INB_DOORBELL, sc->out_doorbell); + /* wait for the fw to do it */ + if (arc_wait_doorbell(sc, ARC_RE_OUTB_DOORBELL, ARC_RE_I2D_MSG_CMD_DONE) != 0) + return (1); + + /* ack it */ + arc_write(sc, ARC_RE_INTR_STAT, 0); + break; } return (0); } @@ -2878,9 +3526,9 @@ arc_dmamem_free(struct arc_softc *sc, struct arc_dmame int arc_alloc_ccbs(struct arc_softc *sc) { - struct arc_ccb *ccb; - u_int8_t *cmd; - u_int32_t i, size, len; + struct arc_ccb *ccb; + u_int8_t *cmd; + u_int32_t i, size, iolen; SLIST_INIT(&sc->sc_ccb_free); mtx_init(&sc->sc_ccb_mtx, IPL_BIO); @@ -2888,16 +3536,30 @@ arc_alloc_ccbs(struct arc_softc *sc) size = sizeof(struct arc_ccb) * ARCMSR_MAX_CCB_COUNT; sc->sc_ccbs = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); - len = ARC_IO_CMD_LEN; - size = ARCMSR_MAX_CCB_COUNT * len; - if(sc->sc_adp_type == ARC_HBA_TYPE_D) + size = ARCMSR_MAX_CCB_COUNT * ARC_IO_CMD_LEN; + iolen = size; + switch(sc->sc_adp_type) { + case ARC_HBA_TYPE_B: + size += sizeof(struct arc_HBB_Msgu); + break; + case ARC_HBA_TYPE_D: size += sizeof(struct arc_HBD_Msgu); + sc->ioc_compq_size = size; + break; + case ARC_HBA_TYPE_E: + size += ARC_HBE_COMPLETION_Q_LEN; + sc->doneq_size = ARC_HBE_COMPLETION_Q_LEN; + sc->doneq_entry = ARC_HBE_COMPLETION_Q_LEN / sizeof(struct arc_HBE_Msgu); + sc->doneq_index = 0; + break; + } sc->sc_requests = arc_dmamem_alloc(sc, size); if (sc->sc_requests == NULL) { printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc)); goto free_ccbs; } cmd = ARC_DMA_KVA(sc->sc_requests); + sc->sc_ccb_phys_lo = ARC_DMA_DVA(sc->sc_requests); for (i = 0; i < ARCMSR_MAX_CCB_COUNT; i++) { ccb = &sc->sc_ccbs[i]; @@ -2910,25 +3572,52 @@ arc_alloc_ccbs(struct arc_softc *sc) } ccb->ccb_sc = sc; - ccb->cmd_dma_offset = len * i; + ccb->cmd_dma_offset = ARC_IO_CMD_LEN * i; + ccb->ccb_id = i; + ccb->smid = i << 16; ccb->ccb_cmd = (struct arc_io_cmd *)&cmd[ccb->cmd_dma_offset]; ccb->ccb_cmd_post = (ARC_DMA_DVA(sc->sc_requests) + ccb->cmd_dma_offset); - if ((sc->sc_adp_type != ARC_HBA_TYPE_C) && - (sc->sc_adp_type != ARC_HBA_TYPE_D)) + if ((sc->sc_adp_type == ARC_HBA_TYPE_A) || + (sc->sc_adp_type == ARC_HBA_TYPE_B)) ccb->ccb_cmd_post = ccb->ccb_cmd_post >> ARC_RA_POST_QUEUE_ADDR_SHIFT; arc_put_ccb(sc, ccb); } sc->sc_ccb_phys_hi = (u_int64_t)ARC_DMA_DVA(sc->sc_requests) >> 32; - if(sc->sc_adp_type == ARC_HBA_TYPE_D) { - sc->postQ_buffer = ARC_DMA_DVA(sc->sc_requests) + - (ARCMSR_MAX_CCB_COUNT * len); + switch(sc->sc_adp_type) { + case ARC_HBA_TYPE_B: + sc->postQ_buffer = ARC_DMA_DVA(sc->sc_requests) + iolen; + sc->doneQ_buffer = sc->postQ_buffer + (sizeof(u_int32_t) * + ARCMSR_MAX_HBB_POSTQUEUE); + sc->pmuB = (struct arc_HBB_Msgu *)&cmd[iolen]; + sc->cmdQ_ptr_offset = iolen; + if (sc->ab_product == PCI_PRODUCT_ARECA_ARC1203) { + sc->inb_doorbell = (bus_size_t)ARC_RB_INB_DOORBELL_1203; + sc->inb_doorbell_mask = (bus_size_t)ARC_RB_INB_DOORBELL_MASK_1203; + sc->outb_doorbell = (bus_size_t)ARC_RB_OUTB_DOORBELL_1203; + sc->outb_doorbell_mask = (bus_size_t)ARC_RB_OUTB_DOORBELL_MASK_1203; + } else { + sc->inb_doorbell = (bus_size_t)ARC_RB_INB_DOORBELL; + sc->inb_doorbell_mask = (bus_size_t)ARC_RB_INB_DOORBELL_MASK; + sc->outb_doorbell = (bus_size_t)ARC_RB_OUTB_DOORBELL; + sc->outb_doorbell_mask = (bus_size_t)ARC_RB_OUTB_DOORBELL_MASK; + } + break; + case ARC_HBA_TYPE_D: + sc->postQ_buffer = ARC_DMA_DVA(sc->sc_requests) + iolen; sc->doneQ_buffer = sc->postQ_buffer + (sizeof(struct InBound_SRB) * ARCMSR_MAX_HBD_POSTQUEUE); - sc->pmu = (struct arc_HBD_Msgu *)&cmd[ARCMSR_MAX_CCB_COUNT * len]; - sc->cmdQ_ptr_offset = ARCMSR_MAX_CCB_COUNT * len; + sc->pmu = (struct arc_HBD_Msgu *)&cmd[iolen]; + sc->cmdQ_ptr_offset = iolen; + break; + case ARC_HBA_TYPE_E: + sc->pmuE = (struct arc_HBE_Msgu *)&cmd[iolen]; + sc->doneq_phys_lo = ARC_DMA_DVA(sc->sc_requests) + iolen; + sc->doneq_phys_hi = (u_int64_t)(ARC_DMA_DVA(sc->sc_requests) + iolen) >> 32; + sc->cmdQ_ptr_offset = iolen; + break; } scsi_iopool_init(&sc->sc_iopool, sc, (void *(*)(void *))arc_get_ccb, diff -upN a/sys/dev/pci/pcidevs b/sys/dev/pci/pcidevs --- a/sys/dev/pci/pcidevs Mon Jul 6 19:24:58 2020 +++ b/sys/dev/pci/pcidevs Mon Jul 6 19:25:30 2020 @@ -1031,6 +1031,7 @@ product ARECA ARC1200 0x1200 ARC-1200 product ARECA ARC1200_B 0x1201 ARC-1200B product ARECA ARC1202 0x1202 ARC-1202 product ARECA ARC1210 0x1210 ARC-1210 +product ARECA ARC1203 0X1203 ARC-1203 product ARECA ARC1214 0x1214 ARC-1214 product ARECA ARC1220 0x1220 ARC-1220 product ARECA ARC1230 0x1230 ARC-1230 @@ -1042,6 +1043,8 @@ product ARECA ARC1381 0x1381 ARC-1381 product ARECA ARC1680 0x1680 ARC-1680 product ARECA ARC1681 0x1681 ARC-1681 product ARECA ARC1880 0x1880 ARC-1880 +product ARECA ARC1884 0x1884 ARC-1884 +product ARECA ARC1886 0x188a ARC-1886 /* ASIX Electronics products */ product ASIX AX88140A 0x1400 AX88140A/88141
