svn commit: r242214 - in stable/9: share/man/man4 sys/dev/hptiop
Xin LI
delphij at FreeBSD.org
Sun Oct 28 10:18:47 UTC 2012
Author: delphij
Date: Sun Oct 28 10:18:46 2012
New Revision: 242214
URL: http://svn.freebsd.org/changeset/base/242214
Log:
MFC r242086:
Update hptiop(4) to version 1.8, which added support for HighPoint
RocketRAID 4500 series.
Many thanks to HighPoint Technologies for their continued support
of FreeBSD!
Submitted by: HighPoint Technologies
Modified:
stable/9/share/man/man4/hptiop.4
stable/9/sys/dev/hptiop/hptiop.c
stable/9/sys/dev/hptiop/hptiop.h
Directory Properties:
stable/9/share/man/man4/ (props changed)
stable/9/sys/ (props changed)
stable/9/sys/dev/ (props changed)
Modified: stable/9/share/man/man4/hptiop.4
==============================================================================
--- stable/9/share/man/man4/hptiop.4 Sun Oct 28 10:11:47 2012 (r242213)
+++ stable/9/share/man/man4/hptiop.4 Sun Oct 28 10:18:46 2012 (r242214)
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 5, 2012
+.Dd October 25, 2012
.Dt HPTIOP 4
.Os
.Sh NAME
@@ -58,6 +58,10 @@ driver supports the following SAS and SA
.Pp
.Bl -bullet -compact
.It
+HighPoint RocketRAID 4522
+.It
+HighPoint RocketRAID 4520
+.It
HighPoint RocketRAID 4322
.It
HighPoint RocketRAID 4321
Modified: stable/9/sys/dev/hptiop/hptiop.c
==============================================================================
--- stable/9/sys/dev/hptiop/hptiop.c Sun Oct 28 10:11:47 2012 (r242213)
+++ stable/9/sys/dev/hptiop/hptiop.c Sun Oct 28 10:18:46 2012 (r242214)
@@ -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
@@ -89,8 +89,8 @@ __FBSDID("$FreeBSD$");
#include <dev/hptiop/hptiop.h>
-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;
@@ -99,41 +99,62 @@ static int hptiop_send_sync_msg(struct h
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 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);
@@ -146,8 +167,7 @@ static void hptiop_async(void *callback_
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;
@@ -193,6 +213,11 @@ static struct cdevsw hptiop_cdevsw = {
#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(ioctl_dev_t dev, int flags,
int devtype, ioctl_thread_t proc)
{
@@ -294,6 +319,12 @@ static void hptiop_post_msg_mv(struct hp
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;
@@ -323,6 +354,15 @@ static int hptiop_wait_ready_mv(struct h
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)
{
@@ -618,6 +658,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;
+
+ untimeout(hptiop_reset_adapter, hba, 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;
@@ -656,6 +801,50 @@ static int hptiop_intr_mv(struct hpt_iop
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)
{
@@ -702,6 +891,48 @@ static int hptiop_send_sync_request_mv(s
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)
{
@@ -776,6 +1007,37 @@ static int hptiop_get_config_mv(struct h
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)
{
@@ -833,6 +1095,31 @@ static int hptiop_set_config_mv(struct h
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)
@@ -884,7 +1171,8 @@ static int hptiop_post_ioctl_command_itl
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;
@@ -898,7 +1186,8 @@ static int hptiop_bus_space_copyin(struc
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;
@@ -1045,6 +1334,103 @@ 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, PPAUSE,
+ "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;
@@ -1063,6 +1449,7 @@ static int hptiop_rescan_bus(struct hpt
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)
{
@@ -1139,6 +1526,56 @@ static int hptiop_alloc_pci_res_mv(struc
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)
@@ -1156,6 +1593,16 @@ static void hptiop_release_pci_res_mv(st
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,
@@ -1172,7 +1619,7 @@ static int hptiop_internal_memalloc_mv(s
NULL,
NULL,
#endif
- &hba->ctlcfg_dmat)) {
+ &hba->ctlcfg_dmat)) {
device_printf(hba->pcidev, "alloc ctlcfg_dmat failed\n");
return -1;
}
@@ -1205,6 +1652,72 @@ static int hptiop_internal_memalloc_mv(s
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,
+#if __FreeBSD_version > 502000
+ NULL,
+ NULL,
+#endif
+ &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,
+#if __FreeBSD_version>501000
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT,
+#else
+ BUS_DMA_WAITOK,
+#endif
+ &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) {
@@ -1217,6 +1730,54 @@ static int hptiop_internal_memfree_mv(st
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
*/
@@ -1230,9 +1791,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,
@@ -1243,9 +1805,11 @@ static struct hptiop_adapter_ops hptiop_
.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,
@@ -1259,6 +1823,25 @@ static struct hptiop_adapter_ops hptiop_
.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 = {
@@ -1284,6 +1867,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:
@@ -1385,7 +1973,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;
@@ -1404,6 +1992,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 */
@@ -1542,6 +2141,7 @@ static int hptiop_attach(device_t dev)
}
hba->ops->enable_intr(hba);
+ hba->initialized = 1;
hba->ioctl_dev = make_dev(&hptiop_cdevsw, unit,
UID_ROOT, GID_WHEEL /*GID_OPERATOR*/,
@@ -1587,8 +2187,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)
@@ -1682,6 +2281,18 @@ static void hptiop_enable_intr_mv(struct
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;
@@ -1704,9 +2315,24 @@ static void hptiop_disable_intr_mv(struc
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)
@@ -1910,7 +2536,8 @@ static void hptiop_post_req_itl(struct h
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;
@@ -1956,7 +2583,8 @@ static void hptiop_post_req_itl(struct h
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;
@@ -2044,6 +2672,78 @@ static void hptiop_post_req_mv(struct hp
| (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);
+ }
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-9
mailing list