From ca8956adfa7d29795ec4317cee0ae0269fdc42e8 Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Wed, 21 Nov 2012 04:26:47 +0100 Subject: [PATCH] hptiop(4): Add support for RocketRAID 4520 and 4522. This adds support for HighPoint's recent 6Gb/s SAS/SATA RAID cards. It's not tested in DragonFly, unfortunately, due to lack of hardware, but I'm confident. :) Taken-from: FreeBSD --- share/man/man4/hptiop.4 | 8 +- sys/dev/raid/hptiop/hptiop.c | 766 ++++++++++++++++++++++++++++++++++- sys/dev/raid/hptiop/hptiop.h | 100 ++++- 3 files changed, 849 insertions(+), 25 deletions(-) diff --git a/share/man/man4/hptiop.4 b/share/man/man4/hptiop.4 index ac70a35046..142247940f 100644 --- a/share/man/man4/hptiop.4 +++ b/share/man/man4/hptiop.4 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/share/man/man4/hptiop.4,v 1.3 2011/08/01 21:12:41 delphij Exp $ +.\" $FreeBSD: src/share/man/man4/hptiop.4,v 1.6 2012/10/25 17:29:11 delphij Exp $ .\" -.Dd August 7, 2012 +.Dd November 21, 2012 .Dt HPTIOP 4 .Os .Sh NAME @@ -58,6 +58,10 @@ driver supports the following SAS and SATA RAID controllers: .Pp .Bl -bullet -compact .It +HighPoint RocketRAID 4522 +.It +HighPoint RocketRAID 4520 +.It HighPoint RocketRAID 4322 .It HighPoint RocketRAID 4321 diff --git a/sys/dev/raid/hptiop/hptiop.c b/sys/dev/raid/hptiop/hptiop.c index 1c88d1b4f2..f1468d1e6f 100644 --- a/sys/dev/raid/hptiop/hptiop.c +++ b/sys/dev/raid/hptiop/hptiop.c @@ -1,6 +1,6 @@ /* * HighPoint RR3xxx/4xxx RAID Driver for FreeBSD - * Copyright (C) 2007-2008 HighPoint Technologies, Inc. All Rights Reserved. + * Copyright (C) 2007-2012 HighPoint Technologies, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/hptiop/hptiop.c,v 1.14 2012/08/06 05:27:26 delphij Exp $ + * $FreeBSD: src/sys/dev/hptiop/hptiop.c,v 1.15 2012/10/25 17:29:11 delphij Exp $ */ #include @@ -69,8 +69,8 @@ #include -static char driver_name[] = "hptiop"; -static char driver_version[] = "v1.3 (010208)"; +static const char driver_name[] = "hptiop"; +static const char driver_version[] = "v1.8"; static devclass_t hptiop_devclass; @@ -79,42 +79,63 @@ static int hptiop_send_sync_msg(struct hpt_iop_hba *hba, static void hptiop_request_callback_itl(struct hpt_iop_hba *hba, u_int32_t req); static void hptiop_request_callback_mv(struct hpt_iop_hba *hba, u_int64_t req); +static void hptiop_request_callback_mvfrey(struct hpt_iop_hba *hba, + u_int32_t req); static void hptiop_os_message_callback(struct hpt_iop_hba *hba, u_int32_t msg); static int hptiop_do_ioctl_itl(struct hpt_iop_hba *hba, struct hpt_iop_ioctl_param *pParams); static int hptiop_do_ioctl_mv(struct hpt_iop_hba *hba, struct hpt_iop_ioctl_param *pParams); +static int hptiop_do_ioctl_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_ioctl_param *pParams); static void hptiop_bus_scan_cb(struct cam_periph *periph, union ccb *ccb); static int hptiop_rescan_bus(struct hpt_iop_hba *hba); static int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba); static int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba); +static int hptiop_alloc_pci_res_mvfrey(struct hpt_iop_hba *hba); static int hptiop_get_config_itl(struct hpt_iop_hba *hba, struct hpt_iop_request_get_config *config); static int hptiop_get_config_mv(struct hpt_iop_hba *hba, struct hpt_iop_request_get_config *config); +static int hptiop_get_config_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_request_get_config *config); static int hptiop_set_config_itl(struct hpt_iop_hba *hba, struct hpt_iop_request_set_config *config); static int hptiop_set_config_mv(struct hpt_iop_hba *hba, struct hpt_iop_request_set_config *config); +static int hptiop_set_config_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_request_set_config *config); static int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba); +static int hptiop_internal_memalloc_mvfrey(struct hpt_iop_hba *hba); +static int hptiop_internal_memfree_itl(struct hpt_iop_hba *hba); static int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba); +static int hptiop_internal_memfree_mvfrey(struct hpt_iop_hba *hba); static int hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba, u_int32_t req32, struct hpt_iop_ioctl_param *pParams); static int hptiop_post_ioctl_command_mv(struct hpt_iop_hba *hba, struct hpt_iop_request_ioctl_command *req, struct hpt_iop_ioctl_param *pParams); +static int hptiop_post_ioctl_command_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_request_ioctl_command *req, + struct hpt_iop_ioctl_param *pParams); static void hptiop_post_req_itl(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb, bus_dma_segment_t *segs, int nsegs); static void hptiop_post_req_mv(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb, bus_dma_segment_t *segs, int nsegs); +static void hptiop_post_req_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_srb *srb, + bus_dma_segment_t *segs, int nsegs); static void hptiop_post_msg_itl(struct hpt_iop_hba *hba, u_int32_t msg); static void hptiop_post_msg_mv(struct hpt_iop_hba *hba, u_int32_t msg); +static void hptiop_post_msg_mvfrey(struct hpt_iop_hba *hba, u_int32_t msg); static void hptiop_enable_intr_itl(struct hpt_iop_hba *hba); static void hptiop_enable_intr_mv(struct hpt_iop_hba *hba); +static void hptiop_enable_intr_mvfrey(struct hpt_iop_hba *hba); static void hptiop_disable_intr_itl(struct hpt_iop_hba *hba); static void hptiop_disable_intr_mv(struct hpt_iop_hba *hba); +static void hptiop_disable_intr_mvfrey(struct hpt_iop_hba *hba); static void hptiop_free_srb(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb); static int hptiop_os_query_remove_device(struct hpt_iop_hba *hba, int tid); static int hptiop_probe(device_t dev); @@ -127,8 +148,7 @@ static void hptiop_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); static void hptiop_pci_intr(void *arg); static void hptiop_release_resource(struct hpt_iop_hba *hba); -static int hptiop_reset_adapter(struct hpt_iop_hba *hba); - +static void hptiop_reset_adapter(void *argv); static d_open_t hptiop_open; static d_close_t hptiop_close; static d_ioctl_t hptiop_ioctl; @@ -156,6 +176,11 @@ static struct dev_ops hptiop_ops = { #define BUS_SPACE_RD4_MV2(offset) bus_space_read_4(hba->bar2t,\ hba->bar2h, offsetof(struct hpt_iopmu_mv, offset)) +#define BUS_SPACE_WRT4_MVFREY2(offset, value) bus_space_write_4(hba->bar2t,\ + hba->bar2h, offsetof(struct hpt_iopmu_mvfrey, offset), value) +#define BUS_SPACE_RD4_MVFREY2(offset) bus_space_read_4(hba->bar2t,\ + hba->bar2h, offsetof(struct hpt_iopmu_mvfrey, offset)) + static int hptiop_open(struct dev_open_args *ap) { cdev_t dev = ap->a_head.a_dev; @@ -255,6 +280,12 @@ static void hptiop_post_msg_mv(struct hpt_iop_hba *hba, u_int32_t msg) BUS_SPACE_RD4_MV0(outbound_intmask); } +static void hptiop_post_msg_mvfrey(struct hpt_iop_hba *hba, u_int32_t msg) +{ + BUS_SPACE_WRT4_MVFREY2(f0_to_cpu_msg_a, msg); + BUS_SPACE_RD4_MVFREY2(f0_to_cpu_msg_a); +} + static int hptiop_wait_ready_itl(struct hpt_iop_hba * hba, u_int32_t millisec) { u_int32_t req=0; @@ -284,6 +315,15 @@ static int hptiop_wait_ready_mv(struct hpt_iop_hba * hba, u_int32_t millisec) return 0; } +static int hptiop_wait_ready_mvfrey(struct hpt_iop_hba * hba, + u_int32_t millisec) +{ + if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec)) + return -1; + + return 0; +} + static void hptiop_request_callback_itl(struct hpt_iop_hba * hba, u_int32_t index) { @@ -575,6 +615,111 @@ scsi_done: } } +static void hptiop_request_callback_mvfrey(struct hpt_iop_hba * hba, + u_int32_t _tag) +{ + u_int32_t req_type = _tag & 0xf; + + struct hpt_iop_srb *srb; + struct hpt_iop_request_scsi_command *req; + union ccb *ccb; + u_int8_t *cdb; + + switch (req_type) { + case IOP_REQUEST_TYPE_GET_CONFIG: + case IOP_REQUEST_TYPE_SET_CONFIG: + hba->config_done = 1; + break; + + case IOP_REQUEST_TYPE_SCSI_COMMAND: + srb = hba->srb[(_tag >> 4) & 0xff]; + req = (struct hpt_iop_request_scsi_command *)srb; + + ccb = (union ccb *)srb->ccb; + + callout_stop(&ccb->ccb_h.timeout_ch); + + if (ccb->ccb_h.flags & CAM_CDB_POINTER) + cdb = ccb->csio.cdb_io.cdb_ptr; + else + cdb = ccb->csio.cdb_io.cdb_bytes; + + if (cdb[0] == SYNCHRONIZE_CACHE) { /* ??? */ + ccb->ccb_h.status = CAM_REQ_CMP; + goto scsi_done; + } + + if (_tag & MVFREYIOPMU_QUEUE_REQUEST_RESULT_BIT) + req->header.result = IOP_RESULT_SUCCESS; + + switch (req->header.result) { + case IOP_RESULT_SUCCESS: + switch (ccb->ccb_h.flags & CAM_DIR_MASK) { + case CAM_DIR_IN: + bus_dmamap_sync(hba->io_dmat, + srb->dma_map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(hba->io_dmat, srb->dma_map); + break; + case CAM_DIR_OUT: + bus_dmamap_sync(hba->io_dmat, + srb->dma_map, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(hba->io_dmat, srb->dma_map); + break; + } + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case IOP_RESULT_BAD_TARGET: + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + break; + case IOP_RESULT_BUSY: + ccb->ccb_h.status = CAM_BUSY; + break; + case IOP_RESULT_INVALID_REQUEST: + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + case IOP_RESULT_FAIL: + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + break; + case IOP_RESULT_RESET: + ccb->ccb_h.status = CAM_BUSY; + break; + case IOP_RESULT_CHECK_CONDITION: + memset(&ccb->csio.sense_data, 0, + sizeof(ccb->csio.sense_data)); + if (req->dataxfer_length < ccb->csio.sense_len) + ccb->csio.sense_resid = ccb->csio.sense_len - + req->dataxfer_length; + else + ccb->csio.sense_resid = 0; + memcpy(&ccb->csio.sense_data, &req->sg_list, + MIN(req->dataxfer_length, sizeof(ccb->csio.sense_data))); + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + break; + default: + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + break; + } +scsi_done: + ccb->csio.resid = ccb->csio.dxfer_len - req->dataxfer_length; + + hptiop_free_srb(hba, srb); + xpt_done(ccb); + break; + case IOP_REQUEST_TYPE_IOCTL_COMMAND: + if (_tag & MVFREYIOPMU_QUEUE_REQUEST_RESULT_BIT) + hba->config_done = 1; + else + hba->config_done = -1; + wakeup((struct hpt_iop_request_ioctl_command *)hba->ctlcfg_ptr); + break; + default: + device_printf(hba->pcidev, "wrong callback type\n"); + break; + } +} + static void hptiop_drain_outbound_queue_mv(struct hpt_iop_hba * hba) { u_int64_t req; @@ -613,6 +758,50 @@ static int hptiop_intr_mv(struct hpt_iop_hba * hba) return ret; } +static int hptiop_intr_mvfrey(struct hpt_iop_hba * hba) +{ + u_int32_t status, _tag, cptr; + int ret = 0; + + if (hba->initialized) { + BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0); + } + + status = BUS_SPACE_RD4_MVFREY2(f0_doorbell); + if (status) { + BUS_SPACE_WRT4_MVFREY2(f0_doorbell, status); + if (status & CPU_TO_F0_DRBL_MSG_A_BIT) { + u_int32_t msg = BUS_SPACE_RD4_MVFREY2(cpu_to_f0_msg_a); + hptiop_os_message_callback(hba, msg); + } + ret = 1; + } + + status = BUS_SPACE_RD4_MVFREY2(isr_cause); + if (status) { + BUS_SPACE_WRT4_MVFREY2(isr_cause, status); + do { + cptr = *hba->u.mvfrey.outlist_cptr & 0xff; + while (hba->u.mvfrey.outlist_rptr != cptr) { + hba->u.mvfrey.outlist_rptr++; + if (hba->u.mvfrey.outlist_rptr == hba->u.mvfrey.list_count) { + hba->u.mvfrey.outlist_rptr = 0; + } + + _tag = hba->u.mvfrey.outlist[hba->u.mvfrey.outlist_rptr].val; + hptiop_request_callback_mvfrey(hba, _tag); + ret = 2; + } + } while (cptr != (*hba->u.mvfrey.outlist_cptr & 0xff)); + } + + if (hba->initialized) { + BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0x1010); + } + + return ret; +} + static int hptiop_send_sync_request_itl(struct hpt_iop_hba * hba, u_int32_t req32, u_int32_t millisec) { @@ -659,6 +848,47 @@ static int hptiop_send_sync_request_mv(struct hpt_iop_hba *hba, return -1; } +static int hptiop_send_sync_request_mvfrey(struct hpt_iop_hba *hba, + void *req, u_int32_t millisec) +{ + u_int32_t i, index; + u_int64_t phy_addr; + struct hpt_iop_request_header *reqhdr = (struct hpt_iop_request_header *)req; + + hba->config_done = 0; + + phy_addr = hba->ctlcfgcmd_phy; + reqhdr->flags = IOP_REQUEST_FLAG_SYNC_REQUEST + | IOP_REQUEST_FLAG_OUTPUT_CONTEXT + | IOP_REQUEST_FLAG_ADDR_BITS + | ((phy_addr >> 16) & 0xffff0000); + reqhdr->context = ((phy_addr & 0xffffffff) << 32 ) + | IOPMU_QUEUE_ADDR_HOST_BIT | reqhdr->type; + + hba->u.mvfrey.inlist_wptr++; + index = hba->u.mvfrey.inlist_wptr & 0x3fff; + + if (index == hba->u.mvfrey.list_count) { + index = 0; + hba->u.mvfrey.inlist_wptr &= ~0x3fff; + hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE; + } + + hba->u.mvfrey.inlist[index].addr = phy_addr; + hba->u.mvfrey.inlist[index].intrfc_len = (reqhdr->size + 3) / 4; + + BUS_SPACE_WRT4_MVFREY2(inbound_write_ptr, hba->u.mvfrey.inlist_wptr); + BUS_SPACE_RD4_MVFREY2(inbound_write_ptr); + + for (i = 0; i < millisec; i++) { + hptiop_intr_mvfrey(hba); + if (hba->config_done) + return 0; + DELAY(1000); + } + return -1; +} + static int hptiop_send_sync_msg(struct hpt_iop_hba *hba, u_int32_t msg, u_int32_t millisec) { @@ -733,6 +963,37 @@ static int hptiop_get_config_mv(struct hpt_iop_hba * hba, return 0; } +static int hptiop_get_config_mvfrey(struct hpt_iop_hba * hba, + struct hpt_iop_request_get_config * config) +{ + struct hpt_iop_request_get_config *info = hba->u.mvfrey.config; + + if (info->header.size != sizeof(struct hpt_iop_request_get_config) || + info->header.type != IOP_REQUEST_TYPE_GET_CONFIG) { + KdPrint(("hptiop: header size %x/%x type %x/%x", + info->header.size, (int)sizeof(struct hpt_iop_request_get_config), + info->header.type, IOP_REQUEST_TYPE_GET_CONFIG)); + return -1; + } + + config->interface_version = info->interface_version; + config->firmware_version = info->firmware_version; + config->max_requests = info->max_requests; + config->request_size = info->request_size; + config->max_sg_count = info->max_sg_count; + config->data_transfer_length = info->data_transfer_length; + config->alignment_mask = info->alignment_mask; + config->max_devices = info->max_devices; + config->sdram_size = info->sdram_size; + + KdPrint(("hptiop: maxreq %x reqsz %x datalen %x maxdev %x sdram %x", + config->max_requests, config->request_size, + config->data_transfer_length, config->max_devices, + config->sdram_size)); + + return 0; +} + static int hptiop_set_config_itl(struct hpt_iop_hba *hba, struct hpt_iop_request_set_config *config) { @@ -790,6 +1051,31 @@ static int hptiop_set_config_mv(struct hpt_iop_hba *hba, return 0; } +static int hptiop_set_config_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_request_set_config *config) +{ + struct hpt_iop_request_set_config *req; + + if (!(req = hba->ctlcfg_ptr)) + return -1; + + memcpy((u_int8_t *)req + sizeof(struct hpt_iop_request_header), + (u_int8_t *)config + sizeof(struct hpt_iop_request_header), + sizeof(struct hpt_iop_request_set_config) - + sizeof(struct hpt_iop_request_header)); + + req->header.type = IOP_REQUEST_TYPE_SET_CONFIG; + req->header.size = sizeof(struct hpt_iop_request_set_config); + req->header.result = IOP_RESULT_PENDING; + + if (hptiop_send_sync_request_mvfrey(hba, req, 20000)) { + KdPrint(("hptiop: set config send cmd failed")); + return -1; + } + + return 0; +} + static int hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba, u_int32_t req32, struct hpt_iop_ioctl_param *pParams) @@ -841,7 +1127,8 @@ static int hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba, return 0; } -static int hptiop_bus_space_copyin(struct hpt_iop_hba *hba, u_int32_t bus, void *user, int size) +static int hptiop_bus_space_copyin(struct hpt_iop_hba *hba, u_int32_t bus, + void *user, int size) { unsigned char byte; int i; @@ -855,7 +1142,8 @@ static int hptiop_bus_space_copyin(struct hpt_iop_hba *hba, u_int32_t bus, void return 0; } -static int hptiop_bus_space_copyout(struct hpt_iop_hba *hba, u_int32_t bus, void *user, int size) +static int hptiop_bus_space_copyout(struct hpt_iop_hba *hba, u_int32_t bus, + void *user, int size) { unsigned char byte; int i; @@ -1002,6 +1290,102 @@ invalid: } } +static int hptiop_post_ioctl_command_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_request_ioctl_command *req, + struct hpt_iop_ioctl_param *pParams) +{ + u_int64_t phy_addr; + u_int32_t index; + + phy_addr = hba->ctlcfgcmd_phy; + + if ((((pParams->nInBufferSize + 3) & ~3) + pParams->nOutBufferSize) > + (hba->max_request_size - + offsetof(struct hpt_iop_request_ioctl_command, buf))) { + device_printf(hba->pcidev, "request size beyond max value"); + return -1; + } + + req->ioctl_code = HPT_CTL_CODE_BSD_TO_IOP(pParams->dwIoControlCode); + req->inbuf_size = pParams->nInBufferSize; + req->outbuf_size = pParams->nOutBufferSize; + req->header.size = offsetof(struct hpt_iop_request_ioctl_command, buf) + + pParams->nInBufferSize; + + req->header.type = IOP_REQUEST_TYPE_IOCTL_COMMAND; + req->header.result = IOP_RESULT_PENDING; + + req->header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST + | IOP_REQUEST_FLAG_OUTPUT_CONTEXT + | IOP_REQUEST_FLAG_ADDR_BITS + | ((phy_addr >> 16) & 0xffff0000); + req->header.context = ((phy_addr & 0xffffffff) << 32 ) + | IOPMU_QUEUE_ADDR_HOST_BIT | req->header.type; + + hba->u.mvfrey.inlist_wptr++; + index = hba->u.mvfrey.inlist_wptr & 0x3fff; + + if (index == hba->u.mvfrey.list_count) { + index = 0; + hba->u.mvfrey.inlist_wptr &= ~0x3fff; + hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE; + } + + hba->u.mvfrey.inlist[index].addr = phy_addr; + hba->u.mvfrey.inlist[index].intrfc_len = (req->header.size + 3) / 4; + + BUS_SPACE_WRT4_MVFREY2(inbound_write_ptr, hba->u.mvfrey.inlist_wptr); + BUS_SPACE_RD4_MVFREY2(inbound_write_ptr); + + while (hba->config_done == 0) { + if (hptiop_sleep(hba, req, 0, "hptctl", HPT_OSM_TIMEOUT) == 0) + continue; + hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000); + } + return 0; +} + +static int hptiop_do_ioctl_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_ioctl_param *pParams) +{ + struct hpt_iop_request_ioctl_command *req; + + if ((pParams->Magic != HPT_IOCTL_MAGIC) && + (pParams->Magic != HPT_IOCTL_MAGIC32)) + return EFAULT; + + req = (struct hpt_iop_request_ioctl_command *)(hba->ctlcfg_ptr); + hba->config_done = 0; + hptiop_lock_adapter(hba); + if (pParams->nInBufferSize) + if (copyin((void *)pParams->lpInBuffer, + req->buf, pParams->nInBufferSize)) + goto invalid; + if (hptiop_post_ioctl_command_mvfrey(hba, req, pParams)) + goto invalid; + + if (hba->config_done == 1) { + if (pParams->nOutBufferSize) + if (copyout(req->buf + + ((pParams->nInBufferSize + 3) & ~3), + (void *)pParams->lpOutBuffer, + pParams->nOutBufferSize)) + goto invalid; + + if (pParams->lpBytesReturned) + if (copyout(&req->bytes_returned, + (void*)pParams->lpBytesReturned, + sizeof(u_int32_t))) + goto invalid; + hptiop_unlock_adapter(hba); + return 0; + } else{ +invalid: + hptiop_unlock_adapter(hba); + return EFAULT; + } +} + static int hptiop_rescan_bus(struct hpt_iop_hba * hba) { union ccb *ccb; @@ -1028,9 +1412,10 @@ static void hptiop_bus_scan_cb(struct cam_periph *periph, union ccb *ccb) kfree(ccb, M_TEMP); } -static bus_dmamap_callback_t hptiop_map_srb; -static bus_dmamap_callback_t hptiop_post_scsi_command; -static bus_dmamap_callback_t hptiop_mv_map_ctlcfg; +static bus_dmamap_callback_t hptiop_map_srb; +static bus_dmamap_callback_t hptiop_post_scsi_command; +static bus_dmamap_callback_t hptiop_mv_map_ctlcfg; +static bus_dmamap_callback_t hptiop_mvfrey_map_ctlcfg; static int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba) { @@ -1107,6 +1492,56 @@ static int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba) return 0; } +static int hptiop_alloc_pci_res_mvfrey(struct hpt_iop_hba *hba) +{ + hba->bar0_rid = 0x10; + hba->bar0_res = bus_alloc_resource_any(hba->pcidev, + SYS_RES_MEMORY, &hba->bar0_rid, RF_ACTIVE); + + if (hba->bar0_res == NULL) { + device_printf(hba->pcidev, "failed to get iop bar0.\n"); + return -1; + } + hba->bar0t = rman_get_bustag(hba->bar0_res); + hba->bar0h = rman_get_bushandle(hba->bar0_res); + hba->u.mvfrey.config = (struct hpt_iop_request_get_config *) + rman_get_virtual(hba->bar0_res); + + if (!hba->u.mvfrey.config) { + bus_release_resource(hba->pcidev, SYS_RES_MEMORY, + hba->bar0_rid, hba->bar0_res); + device_printf(hba->pcidev, "alloc bar0 mem res failed\n"); + return -1; + } + + hba->bar2_rid = 0x18; + hba->bar2_res = bus_alloc_resource_any(hba->pcidev, + SYS_RES_MEMORY, &hba->bar2_rid, RF_ACTIVE); + + if (hba->bar2_res == NULL) { + bus_release_resource(hba->pcidev, SYS_RES_MEMORY, + hba->bar0_rid, hba->bar0_res); + device_printf(hba->pcidev, "failed to get iop bar2.\n"); + return -1; + } + + hba->bar2t = rman_get_bustag(hba->bar2_res); + hba->bar2h = rman_get_bushandle(hba->bar2_res); + hba->u.mvfrey.mu = + (struct hpt_iopmu_mvfrey *)rman_get_virtual(hba->bar2_res); + + if (!hba->u.mvfrey.mu) { + bus_release_resource(hba->pcidev, SYS_RES_MEMORY, + hba->bar0_rid, hba->bar0_res); + bus_release_resource(hba->pcidev, SYS_RES_MEMORY, + hba->bar2_rid, hba->bar2_res); + device_printf(hba->pcidev, "alloc mem bar2 res failed\n"); + return -1; + } + + return 0; +} + static void hptiop_release_pci_res_itl(struct hpt_iop_hba *hba) { if (hba->bar0_res) @@ -1124,6 +1559,16 @@ static void hptiop_release_pci_res_mv(struct hpt_iop_hba *hba) hba->bar2_rid, hba->bar2_res); } +static void hptiop_release_pci_res_mvfrey(struct hpt_iop_hba *hba) +{ + if (hba->bar0_res) + bus_release_resource(hba->pcidev, SYS_RES_MEMORY, + hba->bar0_rid, hba->bar0_res); + if (hba->bar2_res) + bus_release_resource(hba->pcidev, SYS_RES_MEMORY, + hba->bar2_rid, hba->bar2_res); +} + static int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba) { if (bus_dma_tag_create(hba->parent_dmat, @@ -1166,6 +1611,64 @@ static int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba) return 0; } +static int hptiop_internal_memalloc_mvfrey(struct hpt_iop_hba *hba) +{ + u_int32_t list_count = BUS_SPACE_RD4_MVFREY2(inbound_conf_ctl); + + list_count >>= 16; + + if (list_count == 0) { + return -1; + } + + hba->u.mvfrey.list_count = list_count; + hba->u.mvfrey.internal_mem_size = 0x800 + + list_count * sizeof(struct mvfrey_inlist_entry) + + list_count * sizeof(struct mvfrey_outlist_entry) + + sizeof(int); + if (bus_dma_tag_create(hba->parent_dmat, + 1, + 0, + BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, + NULL, NULL, + hba->u.mvfrey.internal_mem_size, + 1, + BUS_SPACE_MAXSIZE_32BIT, + BUS_DMA_ALLOCNOW, + &hba->ctlcfg_dmat)) { + device_printf(hba->pcidev, "alloc ctlcfg_dmat failed\n"); + return -1; + } + + if (bus_dmamem_alloc(hba->ctlcfg_dmat, (void **)&hba->ctlcfg_ptr, + BUS_DMA_WAITOK | BUS_DMA_COHERENT, + &hba->ctlcfg_dmamap) != 0) { + device_printf(hba->pcidev, + "bus_dmamem_alloc failed!\n"); + bus_dma_tag_destroy(hba->ctlcfg_dmat); + return -1; + } + + if (bus_dmamap_load(hba->ctlcfg_dmat, + hba->ctlcfg_dmamap, hba->ctlcfg_ptr, + hba->u.mvfrey.internal_mem_size, + hptiop_mvfrey_map_ctlcfg, hba, 0)) { + device_printf(hba->pcidev, "bus_dmamap_load failed!\n"); + if (hba->ctlcfg_dmat) + bus_dmamem_free(hba->ctlcfg_dmat, + hba->ctlcfg_ptr, hba->ctlcfg_dmamap); + bus_dma_tag_destroy(hba->ctlcfg_dmat); + return -1; + } + + return 0; +} + +static int hptiop_internal_memfree_itl(struct hpt_iop_hba *hba) { + return 0; +} + static int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba) { if (hba->ctlcfg_dmat) { @@ -1178,6 +1681,54 @@ static int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba) return 0; } +static int hptiop_internal_memfree_mvfrey(struct hpt_iop_hba *hba) +{ + if (hba->ctlcfg_dmat) { + bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap); + bus_dmamem_free(hba->ctlcfg_dmat, + hba->ctlcfg_ptr, hba->ctlcfg_dmamap); + bus_dma_tag_destroy(hba->ctlcfg_dmat); + } + + return 0; +} + +static int hptiop_reset_comm_mvfrey(struct hpt_iop_hba *hba) +{ + u_int32_t i = 100; + + if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET_COMM, 3000)) + return -1; + + /* wait 100ms for MCU ready */ + while(i--) { + DELAY(1000); + } + + BUS_SPACE_WRT4_MVFREY2(inbound_base, + hba->u.mvfrey.inlist_phy & 0xffffffff); + BUS_SPACE_WRT4_MVFREY2(inbound_base_high, + (hba->u.mvfrey.inlist_phy >> 16) >> 16); + + BUS_SPACE_WRT4_MVFREY2(outbound_base, + hba->u.mvfrey.outlist_phy & 0xffffffff); + BUS_SPACE_WRT4_MVFREY2(outbound_base_high, + (hba->u.mvfrey.outlist_phy >> 16) >> 16); + + BUS_SPACE_WRT4_MVFREY2(outbound_shadow_base, + hba->u.mvfrey.outlist_cptr_phy & 0xffffffff); + BUS_SPACE_WRT4_MVFREY2(outbound_shadow_base_high, + (hba->u.mvfrey.outlist_cptr_phy >> 16) >> 16); + + hba->u.mvfrey.inlist_wptr = (hba->u.mvfrey.list_count - 1) + | CL_POINTER_TOGGLE; + *hba->u.mvfrey.outlist_cptr = (hba->u.mvfrey.list_count - 1) + | CL_POINTER_TOGGLE; + hba->u.mvfrey.outlist_rptr = hba->u.mvfrey.list_count - 1; + + return 0; +} + /* * CAM driver interface */ @@ -1191,9 +1742,10 @@ static device_method_t driver_methods[] = { }; static struct hptiop_adapter_ops hptiop_itl_ops = { + .family = INTEL_BASED_IOP, .iop_wait_ready = hptiop_wait_ready_itl, .internal_memalloc = 0, - .internal_memfree = 0, + .internal_memfree = hptiop_internal_memfree_itl, .alloc_pci_res = hptiop_alloc_pci_res_itl, .release_pci_res = hptiop_release_pci_res_itl, .enable_intr = hptiop_enable_intr_itl, @@ -1204,9 +1756,11 @@ static struct hptiop_adapter_ops hptiop_itl_ops = { .post_msg = hptiop_post_msg_itl, .post_req = hptiop_post_req_itl, .do_ioctl = hptiop_do_ioctl_itl, + .reset_comm = 0, }; static struct hptiop_adapter_ops hptiop_mv_ops = { + .family = MV_BASED_IOP, .iop_wait_ready = hptiop_wait_ready_mv, .internal_memalloc = hptiop_internal_memalloc_mv, .internal_memfree = hptiop_internal_memfree_mv, @@ -1220,6 +1774,25 @@ static struct hptiop_adapter_ops hptiop_mv_ops = { .post_msg = hptiop_post_msg_mv, .post_req = hptiop_post_req_mv, .do_ioctl = hptiop_do_ioctl_mv, + .reset_comm = 0, +}; + +static struct hptiop_adapter_ops hptiop_mvfrey_ops = { + .family = MVFREY_BASED_IOP, + .iop_wait_ready = hptiop_wait_ready_mvfrey, + .internal_memalloc = hptiop_internal_memalloc_mvfrey, + .internal_memfree = hptiop_internal_memfree_mvfrey, + .alloc_pci_res = hptiop_alloc_pci_res_mvfrey, + .release_pci_res = hptiop_release_pci_res_mvfrey, + .enable_intr = hptiop_enable_intr_mvfrey, + .disable_intr = hptiop_disable_intr_mvfrey, + .get_config = hptiop_get_config_mvfrey, + .set_config = hptiop_set_config_mvfrey, + .iop_intr = hptiop_intr_mvfrey, + .post_msg = hptiop_post_msg_mvfrey, + .post_req = hptiop_post_req_mvfrey, + .do_ioctl = hptiop_do_ioctl_mvfrey, + .reset_comm = hptiop_reset_comm_mvfrey, }; static driver_t hptiop_pci_driver = { @@ -1246,6 +1819,11 @@ static int hptiop_probe(device_t dev) id = pci_get_device(dev); switch (id) { + case 0x4520: + case 0x4522: + sas = 1; + ops = &hptiop_mvfrey_ops; + break; case 0x4210: case 0x4211: case 0x4310: @@ -1338,7 +1916,7 @@ static int hptiop_attach(device_t dev) goto release_pci_res; } - if (hba->ops->internal_memalloc) { + if (hba->ops->family == MV_BASED_IOP) { if (hba->ops->internal_memalloc(hba)) { device_printf(dev, "alloc srb_dmat failed\n"); goto destroy_parent_tag; @@ -1357,6 +1935,17 @@ static int hptiop_attach(device_t dev) hba->max_request_size = iop_config.request_size; hba->max_sg_count = iop_config.max_sg_count; + if (hba->ops->family == MVFREY_BASED_IOP) { + if (hba->ops->internal_memalloc(hba)) { + device_printf(dev, "alloc srb_dmat failed\n"); + goto destroy_parent_tag; + } + if (hba->ops->reset_comm(hba)) { + device_printf(dev, "reset comm failed\n"); + goto get_config_failed; + } + } + if (bus_dma_tag_create(hba->parent_dmat,/* parent */ 4, /* alignment */ BUS_SPACE_MAXADDR_32BIT+1, /* boundary */ @@ -1469,6 +2058,7 @@ static int hptiop_attach(device_t dev) } hba->ops->enable_intr(hba); + hba->initialized = 1; hba->ioctl_dev = make_dev(&hptiop_ops, unit, UID_ROOT, GID_WHEEL /*GID_OPERATOR*/, @@ -1514,8 +2104,7 @@ destroy_io_dmat: bus_dma_tag_destroy(hba->io_dmat); get_config_failed: - if (hba->ops->internal_memfree) - hba->ops->internal_memfree(hba); + hba->ops->internal_memfree(hba); destroy_parent_tag: if (hba->parent_dmat) @@ -1608,6 +2197,18 @@ static void hptiop_enable_intr_mv(struct hpt_iop_hba *hba) BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask); } +static void hptiop_enable_intr_mvfrey(struct hpt_iop_hba *hba) +{ + BUS_SPACE_WRT4_MVFREY2(f0_doorbell_enable, CPU_TO_F0_DRBL_MSG_A_BIT); + BUS_SPACE_RD4_MVFREY2(f0_doorbell_enable); + + BUS_SPACE_WRT4_MVFREY2(isr_enable, 0x1); + BUS_SPACE_RD4_MVFREY2(isr_enable); + + BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0x1010); + BUS_SPACE_RD4_MVFREY2(pcie_f0_int_enable); +} + static void hptiop_disable_intr_itl(struct hpt_iop_hba *hba) { u_int32_t int_mask; @@ -1630,9 +2231,24 @@ static void hptiop_disable_intr_mv(struct hpt_iop_hba *hba) BUS_SPACE_RD4_MV0(outbound_intmask); } -static int hptiop_reset_adapter(struct hpt_iop_hba * hba) +static void hptiop_disable_intr_mvfrey(struct hpt_iop_hba *hba) +{ + BUS_SPACE_WRT4_MVFREY2(f0_doorbell_enable, 0); + BUS_SPACE_RD4_MVFREY2(f0_doorbell_enable); + + BUS_SPACE_WRT4_MVFREY2(isr_enable, 0); + BUS_SPACE_RD4_MVFREY2(isr_enable); + + BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0); + BUS_SPACE_RD4_MVFREY2(pcie_f0_int_enable); +} + +static void hptiop_reset_adapter(void *argv) { - return hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000); + struct hpt_iop_hba * hba = (struct hpt_iop_hba *)argv; + if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000)) + return; + hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000); } static void *hptiop_get_srb(struct hpt_iop_hba * hba) @@ -1827,7 +2443,8 @@ static void hptiop_post_req_itl(struct hpt_iop_hba *hba, bcopy(cdb, req.cdb, ccb->csio.cdb_len); - req.header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list) + req.header.size = + offsetof(struct hpt_iop_request_scsi_command, sg_list) + nsegs*sizeof(struct hpt_iopsg); req.header.type = IOP_REQUEST_TYPE_SCSI_COMMAND; req.header.flags = 0; @@ -1873,7 +2490,8 @@ static void hptiop_post_req_itl(struct hpt_iop_hba *hba, req->channel = 0; req->target = ccb->ccb_h.target_id; req->lun = ccb->ccb_h.target_lun; - req->header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list) + req->header.size = + offsetof(struct hpt_iop_request_scsi_command, sg_list) + nsegs*sizeof(struct hpt_iopsg); req->header.context = (u_int64_t)srb->index | IOPMU_QUEUE_ADDR_HOST_BIT; @@ -1961,6 +2579,79 @@ static void hptiop_post_req_mv(struct hpt_iop_hba *hba, | (size > 3 ? 3 : size), hba); } +static void hptiop_post_req_mvfrey(struct hpt_iop_hba *hba, + struct hpt_iop_srb *srb, + bus_dma_segment_t *segs, int nsegs) +{ + int idx, index; + union ccb *ccb = srb->ccb; + u_int8_t *cdb; + struct hpt_iop_request_scsi_command *req; + u_int64_t req_phy; + + req = (struct hpt_iop_request_scsi_command *)srb; + req_phy = srb->phy_addr; + + if (ccb->csio.dxfer_len && nsegs > 0) { + struct hpt_iopsg *psg = req->sg_list; + for (idx = 0; idx < nsegs; idx++, psg++) { + psg->pci_address = (u_int64_t)segs[idx].ds_addr | 1; + psg->size = segs[idx].ds_len; + psg->eot = 0; + } + psg[-1].eot = 1; + } + if (ccb->ccb_h.flags & CAM_CDB_POINTER) + cdb = ccb->csio.cdb_io.cdb_ptr; + else + cdb = ccb->csio.cdb_io.cdb_bytes; + + bcopy(cdb, req->cdb, ccb->csio.cdb_len); + req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND; + req->header.result = IOP_RESULT_PENDING; + req->dataxfer_length = ccb->csio.dxfer_len; + req->channel = 0; + req->target = ccb->ccb_h.target_id; + req->lun = ccb->ccb_h.target_lun; + req->header.size = sizeof(struct hpt_iop_request_scsi_command) + - sizeof(struct hpt_iopsg) + + nsegs * sizeof(struct hpt_iopsg); + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + bus_dmamap_sync(hba->io_dmat, + srb->dma_map, BUS_DMASYNC_PREREAD); + } + else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + bus_dmamap_sync(hba->io_dmat, + srb->dma_map, BUS_DMASYNC_PREWRITE); + + req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT + | IOP_REQUEST_FLAG_ADDR_BITS + | ((req_phy >> 16) & 0xffff0000); + req->header.context = ((req_phy & 0xffffffff) << 32 ) + | srb->index << 4 + | IOPMU_QUEUE_ADDR_HOST_BIT | req->header.type; + + hba->u.mvfrey.inlist_wptr++; + index = hba->u.mvfrey.inlist_wptr & 0x3fff; + + if (index == hba->u.mvfrey.list_count) { + index = 0; + hba->u.mvfrey.inlist_wptr &= ~0x3fff; + hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE; + } + + hba->u.mvfrey.inlist[index].addr = req_phy; + hba->u.mvfrey.inlist[index].intrfc_len = (req->header.size + 3) / 4; + + BUS_SPACE_WRT4_MVFREY2(inbound_write_ptr, hba->u.mvfrey.inlist_wptr); + BUS_SPACE_RD4_MVFREY2(inbound_write_ptr); + + if (req->header.type == IOP_REQUEST_TYPE_SCSI_COMMAND) { + callout_reset(&ccb->ccb_h.timeout_ch, 20*hz, + hptiop_reset_adapter, hba); + } +} + static void hptiop_post_scsi_command(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { @@ -1993,6 +2684,41 @@ static void hptiop_mv_map_ctlcfg(void *arg, bus_dma_segment_t *segs, & ~0x1F); } +static void hptiop_mvfrey_map_ctlcfg(void *arg, bus_dma_segment_t *segs, + int nsegs, int error) +{ + struct hpt_iop_hba *hba = (struct hpt_iop_hba *)arg; + char *p; + u_int64_t phy; + u_int32_t list_count = hba->u.mvfrey.list_count; + + phy = ((u_int64_t)segs->ds_addr + 0x1F) + & ~(u_int64_t)0x1F; + p = (u_int8_t *)(((unsigned long)hba->ctlcfg_ptr + 0x1F) + & ~0x1F); + + hba->ctlcfgcmd_phy = phy; + hba->ctlcfg_ptr = p; + + p += 0x800; + phy += 0x800; + + hba->u.mvfrey.inlist = (struct mvfrey_inlist_entry *)p; + hba->u.mvfrey.inlist_phy = phy; + + p += list_count * sizeof(struct mvfrey_inlist_entry); + phy += list_count * sizeof(struct mvfrey_inlist_entry); + + hba->u.mvfrey.outlist = (struct mvfrey_outlist_entry *)p; + hba->u.mvfrey.outlist_phy = phy; + + p += list_count * sizeof(struct mvfrey_outlist_entry); + phy += list_count * sizeof(struct mvfrey_outlist_entry); + + hba->u.mvfrey.outlist_cptr = (u_int32_t *)p; + hba->u.mvfrey.outlist_cptr_phy = phy; +} + static void hptiop_map_srb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { @@ -2047,7 +2773,7 @@ static void hptiop_map_srb(void *arg, bus_dma_segment_t *segs, static void hptiop_os_message_callback(struct hpt_iop_hba * hba, u_int32_t msg) { - hba->msg_done = 1; + hba->msg_done = 1; } static int hptiop_os_query_remove_device(struct hpt_iop_hba * hba, diff --git a/sys/dev/raid/hptiop/hptiop.h b/sys/dev/raid/hptiop/hptiop.h index b66584edb5..379c5e21dd 100644 --- a/sys/dev/raid/hptiop/hptiop.h +++ b/sys/dev/raid/hptiop/hptiop.h @@ -1,6 +1,6 @@ /* * HighPoint RR3xxx/4xxx RAID Driver for FreeBSD - * Copyright (C) 2007-2008 HighPoint Technologies, Inc. All Rights Reserved. + * Copyright (C) 2007-2012 HighPoint Technologies, Inc. All Rights Reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/hptiop/hptiop.h,v 1.5 2009/03/25 06:27:56 delphij Exp $ + * $FreeBSD: src/sys/dev/hptiop/hptiop.h,v 1.6 2012/10/25 17:29:11 delphij Exp $ */ #ifndef _HPTIOP_H @@ -114,6 +114,68 @@ struct hpt_iopmv_regs { u_int32_t outbound_intmask; }; +#define CL_POINTER_TOGGLE 0x00004000 +#define CPU_TO_F0_DRBL_MSG_A_BIT 0x02000000 + +#pragma pack(1) +struct hpt_iopmu_mvfrey { + u_int32_t reserved[0x4000 / 4]; + + /* hpt_frey_com_reg */ + u_int32_t inbound_base; /* 0x4000 : 0 */ + u_int32_t inbound_base_high; /* 4 */ + u_int32_t reserved2[(0x18 - 8)/ 4]; + u_int32_t inbound_write_ptr; /* 0x18 */ + u_int32_t inbound_read_ptr; /* 0x1c */ + u_int32_t reserved3[(0x2c - 0x20) / 4]; + u_int32_t inbound_conf_ctl; /* 0x2c */ + u_int32_t reserved4[(0x50 - 0x30) / 4]; + u_int32_t outbound_base; /* 0x50 */ + u_int32_t outbound_base_high; /* 0x54 */ + u_int32_t outbound_shadow_base; /* 0x58 */ + u_int32_t outbound_shadow_base_high; /* 0x5c */ + u_int32_t reserved5[(0x68 - 0x60) / 4]; + u_int32_t outbound_write; /* 0x68 */ + u_int32_t reserved6[(0x70 - 0x6c) / 4]; + u_int32_t outbound_read; /* 0x70 */ + u_int32_t reserved7[(0x88 - 0x74) / 4]; + u_int32_t isr_cause; /* 0x88 */ + u_int32_t isr_enable; /* 0x8c */ + + u_int32_t reserved8[(0x10200 - 0x4090) / 4]; + + /* hpt_frey_intr_ctl intr_ctl */ + u_int32_t main_int_cuase; /* 0x10200: 0 */ + u_int32_t main_irq_enable; /* 4 */ + u_int32_t main_fiq_enable; /* 8 */ + u_int32_t pcie_f0_int_enable; /* 0xc */ + u_int32_t pcie_f1_int_enable; /* 0x10 */ + u_int32_t pcie_f2_int_enable; /* 0x14 */ + u_int32_t pcie_f3_int_enable; /* 0x18 */ + + u_int32_t reserved9[(0x10400 - 0x1021c) / 4]; + + /* hpt_frey_msg_drbl */ + u_int32_t f0_to_cpu_msg_a; /* 0x10400: 0 */ + u_int32_t reserved10[(0x20 - 4) / 4]; + u_int32_t cpu_to_f0_msg_a; /* 0x20 */ + u_int32_t reserved11[(0x80 - 0x24) / 4]; + u_int32_t f0_doorbell; /* 0x80 */ + u_int32_t f0_doorbell_enable; /* 0x84 */ +}; + +struct mvfrey_inlist_entry { + u_int64_t addr; + u_int32_t intrfc_len; + u_int32_t reserved; +}; + +struct mvfrey_outlist_entry { + u_int32_t val; +}; + +#pragma pack() + #define MVIOP_IOCTLCFG_SIZE 0x800 #define MVIOP_MU_QUEUE_ADDR_HOST_MASK (~(0x1full)) #define MVIOP_MU_QUEUE_ADDR_HOST_BIT 4 @@ -135,6 +197,8 @@ struct hpt_iopmv_regs { #define MVIOP_REQUEST_NUMBER_START_BIT 16 +#define MVFREYIOPMU_QUEUE_REQUEST_RESULT_BIT 0x40000000 + enum hpt_iopmu_message { /* host-to-iop messages */ IOPMU_INBOUND_MSG0_NOP = 0, @@ -143,6 +207,7 @@ enum hpt_iopmu_message { IOPMU_INBOUND_MSG0_SHUTDOWN, IOPMU_INBOUND_MSG0_STOP_BACKGROUND_TASK, IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, + IOPMU_INBOUND_MSG0_RESET_COMM, IOPMU_INBOUND_MSG0_MAX = 0xff, /* iop-to-host messages */ IOPMU_OUTBOUND_MSG0_REGISTER_DEVICE_0 = 0x100, @@ -158,6 +223,8 @@ enum hpt_iopmu_message { #define IOP_REQUEST_FLAG_REMAPPED 4 #define IOP_REQUEST_FLAG_OUTPUT_CONTEXT 8 +#define IOP_REQUEST_FLAG_ADDR_BITS 0x40 /* flags[31:16] is phy_addr[47:32] */ + enum hpt_iop_request_type { IOP_REQUEST_TYPE_GET_CONFIG = 0, IOP_REQUEST_TYPE_SET_CONFIG, @@ -178,6 +245,7 @@ enum hpt_iop_result_type { IOP_RESULT_CHECK_CONDITION, }; +#pragma pack(1) struct hpt_iop_request_header { u_int32_t size; u_int32_t type; @@ -278,6 +346,21 @@ struct hpt_iop_hba { struct hpt_iopmv_regs *regs; struct hpt_iopmu_mv *mu; } mv; + struct { + struct hpt_iop_request_get_config *config; + struct hpt_iopmu_mvfrey *mu; + + int internal_mem_size; + int list_count; + struct mvfrey_inlist_entry *inlist; + u_int64_t inlist_phy; + u_int32_t inlist_wptr; + struct mvfrey_outlist_entry *outlist; + u_int64_t outlist_phy; + u_int32_t *outlist_cptr; /* copy pointer shadow */ + u_int64_t outlist_cptr_phy; + u_int32_t outlist_rptr; + } mvfrey; } u; struct hpt_iop_hba *next; @@ -325,7 +408,8 @@ struct hpt_iop_hba { struct resource *ctlcfg_res; void *ctlcfg_handle; u_int64_t ctlcfgcmd_phy; - u_int32_t config_done; + u_int32_t config_done; /* can be negative value */ + u_int32_t initialized:1; /* other resources */ struct cam_sim *sim; @@ -337,7 +421,16 @@ struct hpt_iop_hba { struct hpt_iop_srb* srb[HPT_SRB_MAX_QUEUE_SIZE]; }; +#pragma pack() + +enum hptiop_family { + INTEL_BASED_IOP = 0, + MV_BASED_IOP, + MVFREY_BASED_IOP, + UNKNOWN_BASED_IOP = 0xf +}; struct hptiop_adapter_ops { + enum hptiop_family family; int (*iop_wait_ready)(struct hpt_iop_hba *hba, u_int32_t millisec); int (*internal_memalloc)(struct hpt_iop_hba *hba); int (*internal_memfree)(struct hpt_iop_hba *hba); @@ -353,6 +446,7 @@ struct hptiop_adapter_ops { void (*post_msg)(struct hpt_iop_hba *hba, u_int32_t msg); void (*post_req)(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb, bus_dma_segment_t *segs, int nsegs); int (*do_ioctl)(struct hpt_iop_hba *hba, struct hpt_iop_ioctl_param * pParams); + int (*reset_comm)(struct hpt_iop_hba *hba); }; struct hpt_iop_srb { -- 2.41.0