changeset 13999:f0c04f0fa2ad

3500 Support LSI SAS2008 (Falcon) Skinny FW for mr_sas(7D) Reviewed by: Gordon Ross <gwr@nexenta.com> Reviewed by: Saso Kiselkov <skiselkov.ml@gmail.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Approved by: Garrett D'Amore <garrett@damore.org>
author Dan McDonald <danmcd@nexenta.com>
date Thu, 04 Apr 2013 14:26:49 -0400
parents 4ba0940c01f8
children d8c293f5983b
files usr/src/cmd/mdb/common/modules/mr_sas/mr_sas.c usr/src/pkg/manifests/driver-storage-mr_sas.mf usr/src/uts/common/io/mr_sas/mr_sas.c usr/src/uts/common/io/mr_sas/mr_sas.h usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c
diffstat 5 files changed, 195 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/common/modules/mr_sas/mr_sas.c	Sun Mar 31 04:00:15 2013 +0000
+++ b/usr/src/cmd/mdb/common/modules/mr_sas/mr_sas.c	Thu Apr 04 14:26:49 2013 -0400
@@ -23,6 +23,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
 #include <limits.h>
 #include <sys/mdb_modapi.h>
 #include <sys/sysinfo.h>
@@ -57,15 +61,16 @@
 }
 
 void
-display_targets(struct mrsas_instance m, int verbose)
+display_targets(struct mrsas_instance *m, int verbose)
 {
 	int	tgt;
-	struct mrsas_ld *mr_ldp;
+	struct mrsas_ld mr_ldp[MRDRV_MAX_LD];
+	struct mrsas_tbolt_pd mr_pdp[MRSAS_TBOLT_PD_TGT_MAX];
 	char	device_path[PATH_MAX];
 
 	if (verbose) {
 		*device_path = 0;
-		if (construct_path((uintptr_t)m.dip, device_path) != DCMD_OK) {
+		if (construct_path((uintptr_t)m->dip, device_path) != DCMD_OK) {
 			strcpy(device_path, "couldn't determine device path");
 		}
 	}
@@ -73,29 +78,41 @@
 	mdb_printf("\n");
 	if (verbose)
 		mdb_printf("%s\n", device_path);
-	mdb_printf("dev_type target\n");
-	mdb_printf("----------");
-	mdb_printf("\n");
+	mdb_printf("Physical/Logical Target\n");
+	mdb_printf("-----------------------\n");
+
+	if (mdb_vread(&mr_ldp, sizeof (mr_ldp), (uintptr_t)m->mr_ld_list)
+	    == -1 ||
+	    mdb_vread(&mr_pdp, sizeof (mr_pdp), (uintptr_t)m->mr_tbolt_pd_list)
+	    == -1) {
+		mdb_warn("can't read list of disks");
+		return;
+	}
+
 	for (tgt = 0; tgt < MRDRV_MAX_LD; tgt++) {
-		mr_ldp = (struct mrsas_ld *)&m.mr_ld_list[tgt];
-		if ((mr_ldp != NULL) && (mr_ldp->dip != NULL) &&
-		    (mr_ldp->lun_type == MRSAS_LD_LUN)) {
-			mdb_printf("sd %d", tgt);
-			mdb_printf("\n");
+		if (mr_ldp[tgt].dip != NULL &&
+		    mr_ldp[tgt].lun_type == MRSAS_LD_LUN) {
+			mdb_printf("Logical          sd %d\n", tgt);
+		}
+	}
+	for (tgt = 0; tgt < MRSAS_TBOLT_PD_TGT_MAX; tgt++) {
+		if (mr_pdp[tgt].dip != NULL &&
+		    mr_pdp[tgt].lun_type == MRSAS_TBOLT_PD_LUN) {
+			mdb_printf("Physical         sd %d\n", tgt);
 		}
 	}
 	mdb_printf("\n");
 }
 
 void
-display_deviceinfo(struct mrsas_instance m)
+display_deviceinfo(struct mrsas_instance *m)
 {
 	uint16_t vid, did, svid, sid;
 
-	vid = m.vendor_id;
-	did = m.device_id;
-	svid = m.subsysvid;
-	sid = m.subsysid;
+	vid = m->vendor_id;
+	did = m->device_id;
+	svid = m->subsysvid;
+	sid = m->subsysid;
 
 	mdb_printf("\n");
 	mdb_printf("vendor_id device_id subsysvid subsysid");
@@ -178,10 +195,10 @@
 	mdb_printf("\n");
 
 	if (target_info)
-		display_targets(m, verbose);
+		display_targets(&m, verbose);
 
 	if (device_info)
-		display_deviceinfo(m);
+		display_deviceinfo(&m);
 
 	return (rv);
 }
--- a/usr/src/pkg/manifests/driver-storage-mr_sas.mf	Sun Mar 31 04:00:15 2013 +0000
+++ b/usr/src/pkg/manifests/driver-storage-mr_sas.mf	Thu Apr 04 14:26:49 2013 -0400
@@ -21,7 +21,7 @@
 
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
 #
 
 #
@@ -46,11 +46,15 @@
     alias=pci1000,79 \
     alias=pciex1000,5b \
     alias=pciex1000,5d \
+    alias=pciex1000,71 \
+    alias=pciex1000,73 \
     alias=pciex1000,78 \
     alias=pciex1000,79
 $(i386_ONLY)driver name=mr_sas class=scsi-self-identifying \
     alias=pciex1000,5b \
     alias=pciex1000,5d \
+    alias=pciex1000,71 \
+    alias=pciex1000,73 \
     alias=pciex1000,78 \
     alias=pciex1000,79
 file path=kernel/drv/$(ARCH64)/mr_sas group=sys
--- a/usr/src/uts/common/io/mr_sas/mr_sas.c	Sun Mar 31 04:00:15 2013 +0000
+++ b/usr/src/uts/common/io/mr_sas/mr_sas.c	Thu Apr 04 14:26:49 2013 -0400
@@ -44,7 +44,7 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
- * Copyright 2012 Nexenta System, Inc. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -80,6 +80,15 @@
 #include <sys/fm/util.h>
 #include <sys/fm/io/ddi.h>
 
+/* Macros to help Skinny and stock 2108/MFI live together. */
+#define	WR_IB_PICK_QPORT(addr, instance) \
+	if ((instance)->skinny) { \
+		WR_IB_LOW_QPORT((addr), (instance)); \
+		WR_IB_HIGH_QPORT(0, (instance)); \
+	} else { \
+		WR_IB_QPORT((addr), (instance)); \
+	}
+
 /*
  * Local static data
  */
@@ -135,9 +144,6 @@
 static uint_t	mrsas_isr();
 static uint_t	mrsas_softintr();
 static void	mrsas_undo_resources(dev_info_t *, struct mrsas_instance *);
-static struct mrsas_cmd *get_mfi_pkt(struct mrsas_instance *);
-static void	return_mfi_pkt(struct mrsas_instance *,
-		    struct mrsas_cmd *);
 
 static void	free_space_for_mfi(struct mrsas_instance *);
 static uint32_t	read_fw_status_reg_ppc(struct mrsas_instance *);
@@ -575,6 +581,18 @@
 			instance->tbolt = 1;
 			break;
 
+		case PCI_DEVICE_ID_LSI_SKINNY:
+		case PCI_DEVICE_ID_LSI_SKINNY_NEW:
+			/*
+			 * FALLTHRU to PPC-style functions, but mark this
+			 * instance as Skinny, because the register set is
+			 * slightly different (See WR_IB_PICK_QPORT), and
+			 * certain other features are available to a Skinny
+			 * HBA.
+			 */
+			instance->skinny = 1;
+			/* FALLTHRU */
+
 		case PCI_DEVICE_ID_LSI_2108VDE:
 		case PCI_DEVICE_ID_LSI_2108V:
 			con_log(CL_ANN, (CE_NOTE,
@@ -815,15 +833,11 @@
 		tran->tran_tgt_init	= mrsas_tran_tgt_init;
 		tran->tran_tgt_probe	= scsi_hba_probe;
 		tran->tran_tgt_free	= mrsas_tran_tgt_free;
-		if (instance->tbolt) {
-			tran->tran_init_pkt	=
-			    mrsas_tbolt_tran_init_pkt;
-			tran->tran_start	=
-			    mrsas_tbolt_tran_start;
-		} else {
-			tran->tran_init_pkt	= mrsas_tran_init_pkt;
-			tran->tran_start	= mrsas_tran_start;
-		}
+		tran->tran_init_pkt	= mrsas_tran_init_pkt;
+		if (instance->tbolt)
+			tran->tran_start = mrsas_tbolt_tran_start;
+		else
+			tran->tran_start = mrsas_tran_start;
 		tran->tran_abort	= mrsas_tran_abort;
 		tran->tran_reset	= mrsas_tran_reset;
 		tran->tran_getcap	= mrsas_tran_getcap;
@@ -940,7 +954,7 @@
 		instance->unroll.ldlist_buff = 1;
 
 #ifdef PDSUPPORT
-		if (instance->tbolt) {
+		if (instance->tbolt || instance->skinny) {
 			instance->mr_tbolt_pd_max = MRSAS_TBOLT_PD_TGT_MAX;
 			instance->mr_tbolt_pd_list =
 			    kmem_zalloc(MRSAS_TBOLT_GET_PD_MAX(instance) *
@@ -1663,7 +1677,7 @@
 	}
 
 #ifdef PDSUPPORT
-	else if (instance->tbolt) {
+	else if (instance->tbolt || instance->skinny) {
 		if (instance->mr_tbolt_pd_list[tgt].dip == NULL) {
 			mutex_enter(&instance->config_dev_mtx);
 			instance->mr_tbolt_pd_list[tgt].dip = tgt_dip;
@@ -1701,7 +1715,7 @@
 	}
 
 #ifdef PDSUPPORT
-	else if (instance->tbolt) {
+	else if (instance->tbolt || instance->skinny) {
 		mutex_enter(&instance->config_dev_mtx);
 		instance->mr_tbolt_pd_list[tgt].dip = NULL;
 		mutex_exit(&instance->config_dev_mtx);
@@ -1938,7 +1952,7 @@
 			DTRACE_PROBE2(start_tran_err,
 			    uint16_t, instance->fw_outstanding,
 			    uint16_t, instance->max_fw_cmds);
-			return_mfi_pkt(instance, cmd);
+			mrsas_return_mfi_pkt(instance, cmd);
 			return (TRAN_BUSY);
 		}
 
@@ -1987,7 +2001,7 @@
 		(void) mrsas_common_check(instance, cmd);
 		DTRACE_PROBE2(start_nointr_done, uint8_t, hdr->cmd,
 		    uint8_t, hdr->cmd_status);
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 
 		if (pkt->pkt_comp) {
 			(*pkt->pkt_comp)(pkt);
@@ -2461,8 +2475,8 @@
  * After clearing the frame buffer the context id of the
  * frame buffer SHOULD be restored back.
  */
-static struct mrsas_cmd *
-get_mfi_pkt(struct mrsas_instance *instance)
+struct mrsas_cmd *
+mrsas_get_mfi_pkt(struct mrsas_instance *instance)
 {
 	mlist_t			*head = &instance->cmd_pool_list;
 	struct mrsas_cmd	*cmd = NULL;
@@ -2509,8 +2523,8 @@
 /*
  * return_mfi_pkt : Return a cmd to free command pool
  */
-static void
-return_mfi_pkt(struct mrsas_instance *instance, struct mrsas_cmd *cmd)
+void
+mrsas_return_mfi_pkt(struct mrsas_instance *instance, struct mrsas_cmd *cmd)
 {
 	mutex_enter(&instance->cmd_pool_mtx);
 	/* use mlist_add_tail for debug assistance */
@@ -3162,7 +3176,13 @@
 	INIT_LIST_HEAD(&instance->cmd_pend_list);
 	INIT_LIST_HEAD(&instance->app_cmd_pool_list);
 
-	reserve_cmd = MRSAS_APP_RESERVED_CMDS;
+	/*
+	 * When max_cmd is lower than MRSAS_APP_RESERVED_CMDS, how do I split
+	 * into app_cmd and regular cmd?  For now, just take
+	 * max(1/8th of max, 4);
+	 */
+	reserve_cmd = min(MRSAS_APP_RESERVED_CMDS,
+	    max(max_cmd >> 3, MRSAS_APP_MIN_RESERVED_CMDS));
 
 	for (i = 0; i < reserve_cmd; i++) {
 		cmd = instance->cmd_list[i];
@@ -3276,7 +3296,7 @@
 	if (instance->tbolt) {
 		cmd = get_raid_msg_mfi_pkt(instance);
 	} else {
-		cmd = get_mfi_pkt(instance);
+		cmd = mrsas_get_mfi_pkt(instance);
 	}
 
 	if (!cmd) {
@@ -3299,7 +3319,7 @@
 	if (!ci) {
 		cmn_err(CE_WARN,
 		    "Failed to alloc mem for ctrl info");
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 		return (DDI_FAILURE);
 	}
 
@@ -3358,7 +3378,7 @@
 	if (instance->tbolt) {
 		return_raid_msg_mfi_pkt(instance, cmd);
 	} else {
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 	}
 
 	return (ret);
@@ -3381,7 +3401,7 @@
 	if (instance->tbolt) {
 		cmd = get_raid_msg_mfi_pkt(instance);
 	} else {
-		cmd = get_mfi_pkt(instance);
+		cmd = mrsas_get_mfi_pkt(instance);
 	}
 
 	if (!cmd) {
@@ -3434,7 +3454,7 @@
 	if (instance->tbolt) {
 		return_raid_msg_mfi_pkt(instance, cmd);
 	} else {
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 	}
 
 	atomic_add_16(&instance->fw_outstanding, (-1));
@@ -3569,7 +3589,12 @@
 	}
 
 	/* Build INIT command */
-	cmd = get_mfi_pkt(instance);
+	cmd = mrsas_get_mfi_pkt(instance);
+	if (cmd == NULL) {
+		DTRACE_PROBE2(init_adapter_mfi_err, uint16_t,
+		    instance->fw_outstanding, uint16_t, instance->max_fw_cmds);
+		return (DDI_FAILURE);
+	}
 
 	if (mrsas_build_init_cmd(instance, &cmd) != DDI_SUCCESS) {
 		con_log(CL_ANN,
@@ -3589,7 +3614,7 @@
 
 	if (mrsas_common_check(instance, cmd) != DDI_SUCCESS)
 		goto fail_fw_init;
-	return_mfi_pkt(instance, cmd);
+	mrsas_return_mfi_pkt(instance, cmd);
 
 	if (ctio_enable &&
 	    (instance->func_ptr->read_fw_status_reg(instance) & 0x04000000)) {
@@ -3599,6 +3624,8 @@
 		instance->flag_ieee = 0;
 	}
 
+	ASSERT(!instance->skinny || instance->flag_ieee);
+
 	instance->unroll.alloc_space_mfi = 1;
 	instance->unroll.verBuff = 1;
 
@@ -3609,7 +3636,7 @@
 	(void) mrsas_free_dma_obj(instance, instance->drv_ver_dma_obj);
 
 fail_undo_alloc_mfi_space:
-	return_mfi_pkt(instance, cmd);
+	mrsas_return_mfi_pkt(instance, cmd);
 	free_space_for_mfi(instance);
 
 	return (DDI_FAILURE);
@@ -3761,7 +3788,7 @@
 	}
 
 	if (mrsas_common_check(instance, cmd) != DDI_SUCCESS) {
-		return_mfi_pkt(instance, cmd);
+		return_mfi_app_pkt(instance, cmd);
 		return (DDI_FAILURE);
 	}
 
@@ -3814,7 +3841,7 @@
 			 * to be set
 			 */
 			/* WR_IB_MSG_0(MFI_INIT_CLEAR_HANDSHAKE, instance); */
-			if (!instance->tbolt) {
+			if (!instance->tbolt && !instance->skinny) {
 				WR_IB_DOORBELL(MFI_INIT_CLEAR_HANDSHAKE |
 				    MFI_INIT_HOTPLUG, instance);
 			} else {
@@ -3833,7 +3860,7 @@
 			 * (MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG)
 			 * to be set
 			 */
-			if (!instance->tbolt) {
+			if (!instance->tbolt && !instance->skinny) {
 				WR_IB_DOORBELL(MFI_INIT_HOTPLUG, instance);
 			} else {
 				WR_RESERVED0_REGISTER(MFI_INIT_HOTPLUG,
@@ -3853,7 +3880,7 @@
 			 * to be set
 			 */
 			/* WR_IB_DOORBELL(MFI_INIT_READY, instance); */
-			if (!instance->tbolt) {
+			if (!instance->tbolt && !instance->skinny) {
 				WR_IB_DOORBELL(MFI_RESET_FLAGS, instance);
 			} else {
 				WR_RESERVED0_REGISTER(MFI_RESET_FLAGS,
@@ -3937,7 +3964,8 @@
 		}
 	};
 
-	if (!instance->tbolt) {
+	/* This may also need to apply to Skinny, but for now, don't worry. */
+	if (!instance->tbolt && !instance->skinny) {
 		fw_ctrl = RD_IB_DOORBELL(instance);
 		con_log(CL_ANN1, (CE_CONT,
 		    "mfi_state_transition_to_ready:FW ctrl = 0x%x", fw_ctrl));
@@ -3976,7 +4004,7 @@
 	if (instance->tbolt) {
 		cmd = get_raid_msg_mfi_pkt(instance);
 	} else {
-		cmd = get_mfi_pkt(instance);
+		cmd = mrsas_get_mfi_pkt(instance);
 	}
 
 	if (!cmd) {
@@ -4052,7 +4080,7 @@
 	if (instance->tbolt) {
 		return_raid_msg_mfi_pkt(instance, cmd);
 	} else {
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 	}
 
 	return (ret);
@@ -4105,7 +4133,7 @@
 	if (instance->tbolt) {
 		cmd = get_raid_msg_mfi_pkt(instance);
 	} else {
-		cmd = get_mfi_pkt(instance);
+		cmd = mrsas_get_mfi_pkt(instance);
 	}
 
 	if (!cmd) {
@@ -4151,7 +4179,7 @@
 	if (instance->tbolt) {
 		return_raid_msg_mfi_pkt(instance, cmd);
 	} else {
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 	}
 
 }
@@ -4251,7 +4279,7 @@
 
 #ifdef PDSUPPORT
 	case MR_EVT_PD_REMOVED_EXT: {
-		if (instance->tbolt) {
+		if (instance->tbolt || instance->skinny) {
 			pd_addr = &evt_detail->args.pd_addr;
 			dtype = pd_addr->scsi_dev_type;
 			con_log(CL_DLEVEL1, (CE_NOTE,
@@ -4275,7 +4303,7 @@
 	} /* End of MR_EVT_PD_REMOVED_EXT */
 
 	case MR_EVT_PD_INSERTED_EXT: {
-		if (instance->tbolt) {
+		if (instance->tbolt || instance->skinny) {
 			rval = mrsas_service_evt(instance,
 			    ddi_get16(acc_handle,
 			    &evt_detail->args.pd.device_id),
@@ -4289,7 +4317,7 @@
 	} /* End of MR_EVT_PD_INSERTED_EXT */
 
 	case MR_EVT_PD_STATE_CHANGE: {
-		if (instance->tbolt) {
+		if (instance->tbolt || instance->skinny) {
 			tgt = ddi_get16(acc_handle,
 			    &evt_detail->args.pd.device_id);
 			if ((evt_detail->args.pd_state.prevState ==
@@ -4525,6 +4553,12 @@
 					inq = (struct scsi_inquiry *)
 					    acmd->cmd_buf->b_un.b_addr;
 
+#ifdef PDSUPPORT
+					if (hdr->cmd_status == MFI_STAT_OK) {
+						display_scsi_inquiry(
+						    (caddr_t)inq);
+					}
+#else
 					/* don't expose physical drives to OS */
 					if (acmd->islogical &&
 					    (hdr->cmd_status == MFI_STAT_OK)) {
@@ -4541,6 +4575,7 @@
 						hdr->cmd_status =
 						    MFI_STAT_DEVICE_NOT_FOUND;
 					}
+#endif /* PDSUPPORT */
 				}
 			}
 
@@ -4649,19 +4684,14 @@
 				}
 			}
 
+			mrsas_return_mfi_pkt(instance, cmd);
+
 			/* Call the callback routine */
 			if (((pkt->pkt_flags & FLAG_NOINTR) == 0) &&
 			    pkt->pkt_comp) {
-
-				con_log(CL_DLEVEL1, (CE_NOTE, "mrsas_softintr: "
-				    "posting to scsa cmd %p index %x pkt %p "
-				    "time %llx", (void *)cmd, cmd->index,
-				    (void *)pkt, gethrtime()));
 				(*pkt->pkt_comp)(pkt);
-
 			}
 
-			return_mfi_pkt(instance, cmd);
 			break;
 
 		case MFI_CMD_OP_SMP:
@@ -5088,7 +5118,7 @@
 	*cmd_done = 0;
 
 	/* get the command packet */
-	if (!(cmd = get_mfi_pkt(instance))) {
+	if (!(cmd = mrsas_get_mfi_pkt(instance))) {
 		DTRACE_PROBE2(build_cmd_mfi_err, uint16_t,
 		    instance->fw_outstanding, uint16_t, instance->max_fw_cmds);
 		return (NULL);
@@ -5136,7 +5166,7 @@
 	/*
 	 * case SCMD_SYNCHRONIZE_CACHE:
 	 *	flush_cache(instance);
-	 *	return_mfi_pkt(instance, cmd);
+	 *	mrsas_return_mfi_pkt(instance, cmd);
 	 *	*cmd_done = 1;
 	 *
 	 *	return (NULL);
@@ -5245,7 +5275,7 @@
 
 			break;
 		}
-		/* fall through For all non-rd/wr cmds */
+		/* fall through For all non-rd/wr and physical disk cmds */
 	default:
 
 		switch (pkt->pkt_cdbp[0]) {
@@ -5260,7 +5290,7 @@
 			case 0x3:
 			case 0x4:
 				(void) mrsas_mode_sense_build(pkt);
-				return_mfi_pkt(instance, cmd);
+				mrsas_return_mfi_pkt(instance, cmd);
 				*cmd_done = 1;
 				return (NULL);
 			}
@@ -6294,7 +6324,7 @@
 	if (instance->tbolt) {
 		cmd = get_raid_msg_mfi_pkt(instance);
 	} else {
-		cmd = get_mfi_pkt(instance);
+		cmd = mrsas_get_mfi_pkt(instance);
 	}
 	if (!cmd) {
 		con_log(CL_ANN, (CE_WARN, "mr_sas: "
@@ -6338,7 +6368,7 @@
 	if (instance->tbolt) {
 		return_raid_msg_mfi_pkt(instance, cmd);
 	} else {
-		return_mfi_pkt(instance, cmd);
+		mrsas_return_mfi_pkt(instance, cmd);
 	}
 
 	return (rval);
@@ -6435,7 +6465,7 @@
 	if (instance->tbolt) {
 		cmd = get_raid_msg_mfi_pkt(instance);
 	} else {
-		cmd = get_mfi_pkt(instance);
+		cmd = mrsas_get_mfi_pkt(instance);
 	}
 
 	if (!cmd) {
@@ -6728,7 +6758,7 @@
 
 	mutex_enter(&instance->reg_write_mtx);
 	/* Issue the command to the FW */
-	WR_IB_QPORT((cmd->frame_phys_addr) |
+	WR_IB_PICK_QPORT((cmd->frame_phys_addr) |
 	    (((cmd->frame_count - 1) << 1) | 1), instance);
 	mutex_exit(&instance->reg_write_mtx);
 
@@ -6739,10 +6769,10 @@
  */
 static int
 issue_cmd_in_sync_mode_ppc(struct mrsas_instance *instance,
-struct mrsas_cmd *cmd)
+    struct mrsas_cmd *cmd)
 {
 	int	i;
-	uint32_t	msecs = MFI_POLL_TIMEOUT_SECS * (10 * MILLISEC);
+	uint32_t	msecs = MFI_POLL_TIMEOUT_SECS * MILLISEC;
 	struct mrsas_header *hdr = &cmd->frame->hdr;
 
 	con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_sync_mode_ppc: called"));
@@ -6755,7 +6785,7 @@
 
 		con_log(CL_ANN1, (CE_NOTE, "sync_mode_ppc: "
 		    "issue and return in reset case\n"));
-		WR_IB_QPORT((cmd->frame_phys_addr) |
+		WR_IB_PICK_QPORT((cmd->frame_phys_addr) |
 		    (((cmd->frame_count - 1) << 1) | 1), instance);
 
 		return (DDI_SUCCESS);
@@ -6768,7 +6798,7 @@
 
 	mutex_enter(&instance->reg_write_mtx);
 	/* Issue the command to the FW */
-	WR_IB_QPORT((cmd->frame_phys_addr) |
+	WR_IB_PICK_QPORT((cmd->frame_phys_addr) |
 	    (((cmd->frame_count - 1) << 1) | 1), instance);
 	mutex_exit(&instance->reg_write_mtx);
 
@@ -6810,7 +6840,7 @@
 	ddi_put16(cmd->frame_dma_obj.acc_handle, &frame_hdr->flags, flags);
 
 	/* issue the frame using inbound queue port */
-	WR_IB_QPORT((cmd->frame_phys_addr) |
+	WR_IB_PICK_QPORT((cmd->frame_phys_addr) |
 	    (((cmd->frame_count - 1) << 1) | 1), instance);
 
 	/* wait for cmd_status to change from 0xFF */
@@ -6837,11 +6867,16 @@
 
 	con_log(CL_ANN1, (CE_NOTE, "enable_intr_ppc: called"));
 
-	/* WR_OB_DOORBELL_CLEAR(0xFFFFFFFF, instance); */
-	WR_OB_DOORBELL_CLEAR(OB_DOORBELL_CLEAR_MASK, instance);
-
-	/* WR_OB_INTR_MASK(~0x80000000, instance); */
-	WR_OB_INTR_MASK(~(MFI_REPLY_2108_MESSAGE_INTR_MASK), instance);
+	if (instance->skinny) {
+		/* For SKINNY, write ~0x1, from BSD's mfi driver. */
+		WR_OB_INTR_MASK(0xfffffffe, instance);
+	} else {
+		/* WR_OB_DOORBELL_CLEAR(0xFFFFFFFF, instance); */
+		WR_OB_DOORBELL_CLEAR(OB_DOORBELL_CLEAR_MASK, instance);
+
+		/* WR_OB_INTR_MASK(~0x80000000, instance); */
+		WR_OB_INTR_MASK(~(MFI_REPLY_2108_MESSAGE_INTR_MASK), instance);
+	}
 
 	/* dummy read to force PCI flush */
 	mask = RD_OB_INTR_MASK(instance);
@@ -6860,7 +6895,8 @@
 	con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: before : "
 	    "outbound_intr_mask = 0x%x", RD_OB_INTR_MASK(instance)));
 
-	/* WR_OB_INTR_MASK(0xFFFFFFFF, instance); */
+	/* For now, assume there are no extras needed for Skinny support. */
+
 	WR_OB_INTR_MASK(OB_INTR_MASK, instance);
 
 	con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: after : "
@@ -6886,6 +6922,10 @@
 
 	con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: status = 0x%x", status));
 
+	/*
+	 * NOTE:  Some drivers call out SKINNY here, but the return is the same
+	 * for SKINNY and 2108.
+	 */
 	if (!(status & MFI_REPLY_2108_MESSAGE_INTR)) {
 		ret = DDI_INTR_UNCLAIMED;
 	}
@@ -6898,8 +6938,16 @@
 	if (ret == DDI_INTR_UNCLAIMED) {
 		return (ret);
 	}
-	/* clear the interrupt by writing back the same value */
-	WR_OB_DOORBELL_CLEAR(status, instance);
+
+	/*
+	 * Clear the interrupt by writing back the same value.
+	 * Another case where SKINNY is slightly different.
+	 */
+	if (instance->skinny) {
+		WR_OB_INTR_STATUS(status, instance);
+	} else {
+		WR_OB_DOORBELL_CLEAR(status, instance);
+	}
 
 	/* dummy READ */
 	status = RD_OB_INTR_STATUS(instance);
@@ -7485,7 +7533,7 @@
 		if (lun == 0) {
 			rval = mrsas_config_ld(instance, tgt, lun, childp);
 #ifdef PDSUPPORT
-		} else if (instance->tbolt == 1 && lun != 0) {
+		} else if ((instance->tbolt || instance->skinny) && lun != 0) {
 			rval = mrsas_tbolt_config_pd(instance,
 			    tgt, lun, childp);
 #endif
@@ -7528,7 +7576,7 @@
 
 #ifdef PDSUPPORT
 	/* Config PD devices connected to the card */
-	if (instance->tbolt) {
+	if (instance->tbolt || instance->skinny) {
 		for (tgt = 0; tgt < instance->mr_tbolt_pd_max; tgt++) {
 			(void) mrsas_tbolt_config_pd(instance, tgt, 1, NULL);
 		}
@@ -7782,7 +7830,7 @@
 				(void) mrsas_config_ld(instance, mrevt->tgt,
 				    0, NULL);
 #ifdef PDSUPPORT
-			} else if (instance->tbolt) {
+			} else if (instance->tbolt || instance->skinny) {
 				(void) mrsas_tbolt_config_pd(instance,
 				    mrevt->tgt,
 				    1, NULL);
--- a/usr/src/uts/common/io/mr_sas/mr_sas.h	Sun Mar 31 04:00:15 2013 +0000
+++ b/usr/src/uts/common/io/mr_sas/mr_sas.h	Thu Apr 04 14:26:49 2013 -0400
@@ -43,6 +43,7 @@
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef	_MR_SAS_H_
@@ -90,6 +91,8 @@
  */
 #define	PCI_DEVICE_ID_LSI_2108VDE		0x0078
 #define	PCI_DEVICE_ID_LSI_2108V			0x0079
+#define	PCI_DEVICE_ID_LSI_SKINNY		0x0071
+#define	PCI_DEVICE_ID_LSI_SKINNY_NEW		0x0073
 #define	PCI_DEVICE_ID_LSI_TBOLT			0x005b
 #define	PCI_DEVICE_ID_LSI_INVADER		0x005d
 
@@ -100,6 +103,7 @@
 
 #define	MRSAS_MAX_SGE_CNT			0x50
 #define	MRSAS_APP_RESERVED_CMDS			32
+#define	MRSAS_APP_MIN_RESERVED_CMDS		4
 
 #define	MRSAS_IOCTL_DRIVER			0x12341234
 #define	MRSAS_IOCTL_FIRMWARE			0x12345678
@@ -594,7 +598,8 @@
 
 	uint8_t		fast_path_io;
 
-	uint16_t	tbolt;
+	uint8_t		skinny;
+	uint8_t		tbolt;
 	uint16_t	reply_read_index;
 	uint16_t	reply_size; 		/* Single Reply struct size */
 	uint16_t	raid_io_msg_size; 	/* Single message size */
@@ -2045,6 +2050,9 @@
 
 int mfi_state_transition_to_ready(struct mrsas_instance *);
 
+struct mrsas_cmd *mrsas_get_mfi_pkt(struct mrsas_instance *);
+void mrsas_return_mfi_pkt(struct mrsas_instance *, struct mrsas_cmd *);
+
 
 /* FMA functions. */
 int mrsas_common_check(struct mrsas_instance *, struct  mrsas_cmd *);
--- a/usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c	Sun Mar 31 04:00:15 2013 +0000
+++ b/usr/src/uts/common/io/mr_sas/mr_sas_tbolt.c	Thu Apr 04 14:26:49 2013 -0400
@@ -15,6 +15,10 @@
  *		Shakeel Bukhari
  */
 
+/*
+ * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ */
+
 
 #include <sys/types.h>
 #include <sys/file.h>
@@ -46,8 +50,6 @@
 extern int	debug_level_g;
 extern unsigned int	enable_fp;
 volatile int dump_io_wait_time = 90;
-extern void
-io_timeout_checker(void *arg);
 extern volatile int  debug_timeout_g;
 extern int	mrsas_issue_pending_cmds(struct mrsas_instance *);
 extern int mrsas_complete_pending_cmds(struct mrsas_instance *instance);
@@ -1882,96 +1884,6 @@
 	return (cmd);
 }
 
-/*
- * mrsas_tbolt_tran_init_pkt - allocate & initialize a scsi_pkt structure
- * @ap:
- * @pkt:
- * @bp:
- * @cmdlen:
- * @statuslen:
- * @tgtlen:
- * @flags:
- * @callback:
- *
- * The tran_init_pkt() entry point allocates and initializes a scsi_pkt
- * structure and DMA resources for a target driver request. The
- * tran_init_pkt() entry point is called when the target driver calls the
- * SCSA function scsi_init_pkt(). Each call of the tran_init_pkt() entry point
- * is a request to perform one or more of three possible services:
- *  - allocation and initialization of a scsi_pkt structure
- *  - allocation of DMA resources for data transfer
- *  - reallocation of DMA resources for the next portion of the data transfer
- */
-struct scsi_pkt *
-mrsas_tbolt_tran_init_pkt(struct scsi_address *ap,
-	register struct scsi_pkt *pkt,
-	struct buf *bp, int cmdlen, int statuslen, int tgtlen,
-	int flags, int (*callback)(), caddr_t arg)
-{
-	struct scsa_cmd	*acmd;
-	struct mrsas_instance	*instance;
-	struct scsi_pkt	*new_pkt;
-
-	instance = ADDR2MR(ap);
-
-	/* step #1 : pkt allocation */
-	if (pkt == NULL) {
-		pkt = scsi_hba_pkt_alloc(instance->dip, ap, cmdlen, statuslen,
-		    tgtlen, sizeof (struct scsa_cmd), callback, arg);
-		if (pkt == NULL) {
-			return (NULL);
-		}
-
-		acmd = PKT2CMD(pkt);
-
-		/*
-		 * Initialize the new pkt - we redundantly initialize
-		 * all the fields for illustrative purposes.
-		 */
-		acmd->cmd_pkt		= pkt;
-		acmd->cmd_flags		= 0;
-		acmd->cmd_scblen	= statuslen;
-		acmd->cmd_cdblen	= cmdlen;
-		acmd->cmd_dmahandle	= NULL;
-		acmd->cmd_ncookies	= 0;
-		acmd->cmd_cookie	= 0;
-		acmd->cmd_cookiecnt	= 0;
-		acmd->cmd_nwin		= 0;
-
-		pkt->pkt_address	= *ap;
-		pkt->pkt_comp		= (void (*)())NULL;
-		pkt->pkt_flags		= 0;
-		pkt->pkt_time		= 0;
-		pkt->pkt_resid		= 0;
-		pkt->pkt_state		= 0;
-		pkt->pkt_statistics	= 0;
-		pkt->pkt_reason		= 0;
-		new_pkt			= pkt;
-	} else {
-		acmd = PKT2CMD(pkt);
-		new_pkt = NULL;
-	}
-
-	/* step #2 : dma allocation/move */
-	if (bp && bp->b_bcount != 0) {
-		if (acmd->cmd_dmahandle == NULL) {
-			if (mrsas_dma_alloc(instance, pkt, bp, flags,
-			    callback) == DDI_FAILURE) {
-				if (new_pkt) {
-					scsi_hba_pkt_free(ap, new_pkt);
-				}
-				return ((struct scsi_pkt *)NULL);
-			}
-		} else {
-			if (mrsas_dma_move(instance, pkt, bp) == DDI_FAILURE) {
-				return ((struct scsi_pkt *)NULL);
-			}
-		}
-	}
-	return (pkt);
-}
-
-
 uint32_t
 tbolt_read_fw_status_reg(struct mrsas_instance *instance)
 {
@@ -3632,6 +3544,14 @@
 
 
 #ifdef PDSUPPORT
+/*
+ * Even though these functions were originally intended for 2208 only, it
+ * turns out they're useful for "Skinny" support as well.  In a perfect world,
+ * these two functions would be either in mr_sas.c, or in their own new source
+ * file.  Since this driver needs some cleanup anyway, keep this portion in
+ * mind as well.
+ */
+
 int
 mrsas_tbolt_config_pd(struct mrsas_instance *instance, uint16_t tgt,
     uint8_t lun, dev_info_t **ldip)
@@ -3694,7 +3614,6 @@
 			sd->sd_inq = (struct scsi_inquiry *)NULL;
 		}
 		kmem_free(sd, sizeof (struct scsi_device));
-		rval = NDI_SUCCESS;
 	} else {
 		con_log(CL_ANN1, (CE_NOTE,
 		    "Device not supported: tgt %d lun %d dtype %d",
@@ -3716,7 +3635,12 @@
 	struct mrsas_dcmd_frame	*dcmd;
 	dma_obj_t		dcmd_dma_obj;
 
-	cmd = get_raid_msg_pkt(instance);
+	ASSERT(instance->tbolt || instance->skinny);
+
+	if (instance->tbolt)
+		cmd = get_raid_msg_pkt(instance);
+	else
+		cmd = mrsas_get_mfi_pkt(instance);
 
 	if (!cmd) {
 		con_log(CL_ANN1,
@@ -3761,9 +3685,8 @@
 	cmd->sync_cmd = MRSAS_TRUE;
 	cmd->frame_count = 1;
 
-	if (instance->tbolt) {
+	if (instance->tbolt)
 		mr_sas_tbolt_build_mfi_cmd(instance, cmd);
-	}
 
 	instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd);
 
@@ -3771,6 +3694,10 @@
 	    (uint8_t *)dcmd_dma_obj.buffer, sizeof (struct mrsas_tbolt_pd_info),
 	    DDI_DEV_AUTOINCR);
 	(void) mrsas_free_dma_obj(instance, dcmd_dma_obj);
-	return_raid_msg_pkt(instance, cmd);
+
+	if (instance->tbolt)
+		return_raid_msg_pkt(instance, cmd);
+	else
+		mrsas_return_mfi_pkt(instance, cmd);
 }
 #endif