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