changeset 1006:6478a2efe89e

PSARC 2005/680 new scsi_hba_tran entry points 6352261 hba drivers could make use of a scsi_pkt allocator
author taylor
date Mon, 28 Nov 2005 12:14:38 -0800
parents 815ba7b4dfdf
children 2f6b16d17f28
files usr/src/uts/common/io/scsi/impl/scsi_hba.c usr/src/uts/common/io/scsi/impl/scsi_resource.c usr/src/uts/common/sys/scsi/impl/transport.h usr/src/uts/common/sys/scsi/scsi_pkt.h usr/src/uts/common/sys/scsi/scsi_resource.h
diffstat 5 files changed, 317 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/scsi/impl/scsi_hba.c	Mon Nov 28 11:50:15 2005 -0800
+++ b/usr/src/uts/common/io/scsi/impl/scsi_hba.c	Mon Nov 28 12:14:38 2005 -0800
@@ -38,6 +38,18 @@
 #include <sys/ddi.h>
 #include <sys/epm.h>
 
+extern struct scsi_pkt *scsi_init_cache_pkt(struct scsi_address *,
+		    struct scsi_pkt *, struct buf *, int, int, int, int,
+		    int (*)(caddr_t), caddr_t);
+extern void scsi_free_cache_pkt(struct scsi_address *,
+		    struct scsi_pkt *);
+/*
+ * Round up all allocations so that we can guarantee
+ * long-long alignment.  This is the same alignment
+ * provided by kmem_alloc().
+ */
+#define	ROUNDUP(x)	(((x) + 0x07) & ~0x07)
+
 static kmutex_t	scsi_hba_mutex;
 
 kmutex_t scsi_log_mutex;
@@ -203,7 +215,73 @@
 }
 #endif	/* NO_SCSI_FINI_YET */
 
+int
+scsi_hba_pkt_constructor(void *buf, void *arg, int kmflag)
+{
+	struct scsi_pkt		*pkt;
+	scsi_hba_tran_t		*tran = (scsi_hba_tran_t *)arg;
+	int			pkt_len;
+	char			*ptr;
 
+	pkt = &((struct scsi_pkt_cache_wrapper *)buf)->pcw_pkt;
+
+	/*
+	 * allocate a chunk of memory for the following:
+	 * scsi_pkt
+	 * pkt_ha_private
+	 * pkt_cdbp, if needed
+	 * (pkt_private always null)
+	 * pkt_scbp, if needed
+	 */
+	pkt_len = tran->tran_hba_len + sizeof (struct scsi_pkt_cache_wrapper);
+	if (tran->tran_hba_flags & SCSI_HBA_TRAN_CDB)
+		pkt_len += DEFAULT_CDBLEN;
+	if (tran->tran_hba_flags & SCSI_HBA_TRAN_SCB)
+		pkt_len += DEFAULT_SCBLEN;
+	bzero(buf, pkt_len);
+	ptr = buf;
+	ptr += sizeof (struct scsi_pkt_cache_wrapper);
+	pkt->pkt_ha_private = (opaque_t)ptr;
+	ptr += tran->tran_hba_len;
+	if (tran->tran_hba_flags & SCSI_HBA_TRAN_CDB) {
+		pkt->pkt_cdbp = (opaque_t)ptr;
+		ptr += DEFAULT_CDBLEN;
+	}
+	pkt->pkt_private = NULL;
+	if (tran->tran_hba_flags & SCSI_HBA_TRAN_SCB)
+		pkt->pkt_scbp = (opaque_t)ptr;
+	if (tran->tran_pkt_constructor)
+		return ((*tran->tran_pkt_constructor)(pkt, arg, kmflag));
+	else
+		return (0);
+}
+
+#define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
+
+void
+scsi_hba_pkt_destructor(void *buf, void *arg)
+{
+	struct scsi_pkt		*pkt;
+	scsi_hba_tran_t		*tran = (scsi_hba_tran_t *)arg;
+
+	pkt = &((struct scsi_pkt_cache_wrapper *)buf)->pcw_pkt;
+	if (tran->tran_pkt_destructor)
+		(*tran->tran_pkt_destructor)(pkt, arg);
+
+	/* make sure nobody messed with our pointers */
+	ASSERT(pkt->pkt_ha_private == (opaque_t)((char *)pkt +
+		sizeof (struct scsi_pkt_cache_wrapper)));
+	ASSERT(((tran->tran_hba_flags & SCSI_HBA_TRAN_SCB) == 0) ||
+	    (pkt->pkt_scbp == (opaque_t)((char *)pkt +
+	    tran->tran_hba_len +
+	    (((tran->tran_hba_flags & SCSI_HBA_TRAN_CDB) == 0)
+		? 0 : DEFAULT_CDBLEN) +
+	    DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper))));
+	ASSERT(((tran->tran_hba_flags & SCSI_HBA_TRAN_CDB) == 0) ||
+	    (pkt->pkt_cdbp == (opaque_t)((char *)pkt +
+	    tran->tran_hba_len +
+	    sizeof (struct scsi_pkt_cache_wrapper))));
+}
 
 /*
  * Called by an HBA from _init()
@@ -325,6 +403,34 @@
 	hba_tran->tran_max_burst_size =
 		(1<<(ddi_fls(hba_dma_attr->dma_attr_burstsizes)-1));
 
+	/* create kmem_cache, if needed */
+	if (hba_tran->tran_pkt_constructor) {
+		char tmp[96];
+		int hbalen;
+		int cmdlen = 0;
+		int statuslen = 0;
+
+		ASSERT(hba_tran->tran_init_pkt == NULL);
+		ASSERT(hba_tran->tran_destroy_pkt == NULL);
+
+		hba_tran->tran_init_pkt = scsi_init_cache_pkt;
+		hba_tran->tran_destroy_pkt = scsi_free_cache_pkt;
+
+		hbalen = ROUNDUP(hba_tran->tran_hba_len);
+		if (flags & SCSI_HBA_TRAN_CDB)
+			cmdlen = ROUNDUP(DEFAULT_CDBLEN);
+		if (flags & SCSI_HBA_TRAN_SCB)
+			statuslen = ROUNDUP(DEFAULT_SCBLEN);
+
+		(void) snprintf(tmp, sizeof (tmp), "pkt_cache_%s_%d",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
+		hba_tran->tran_pkt_cache_ptr = kmem_cache_create(tmp,
+		    sizeof (struct scsi_pkt_cache_wrapper) +
+		    hbalen + cmdlen + statuslen, 8,
+		    scsi_hba_pkt_constructor, scsi_hba_pkt_destructor,
+		    NULL, hba_tran, NULL, 0);
+	}
+
 	/*
 	 * Attach scsi configuration property parameters
 	 * to this instance of the hba.
@@ -473,6 +579,10 @@
 	hba->tran_min_burst_size = (uchar_t)0;
 	hba->tran_max_burst_size = (uchar_t)0;
 
+	if (hba->tran_pkt_cache_ptr != NULL) {
+		kmem_cache_destroy(hba->tran_pkt_cache_ptr);
+		hba->tran_pkt_cache_ptr = NULL;
+	}
 	/*
 	 * Remove HBA instance from scsi_hba_list
 	 */
@@ -906,13 +1016,6 @@
 #endif
 
 /*
- * Round up all allocations so that we can guarantee
- * long-long alignment.  This is the same alignment
- * provided by kmem_alloc().
- */
-#define	ROUNDUP(x)	(((x) + 0x07) & ~0x07)
-
-/*
  * Called by an HBA to allocate a scsi_pkt
  */
 /*ARGSUSED*/
--- a/usr/src/uts/common/io/scsi/impl/scsi_resource.c	Mon Nov 28 11:50:15 2005 -0800
+++ b/usr/src/uts/common/io/scsi/impl/scsi_resource.c	Mon Nov 28 12:14:38 2005 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -124,6 +124,163 @@
 		"scsi_free_consistent_buf_end");
 }
 
+void scsi_free_cache_pkt(struct scsi_address *, struct scsi_pkt *);
+
+struct scsi_pkt *
+scsi_init_cache_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
+    struct buf *bp, int cmdlen, int statuslen, int pplen,
+    int flags, int (*callback)(caddr_t), caddr_t callback_arg)
+{
+	struct scsi_pkt_cache_wrapper *pktw;
+	scsi_hba_tran_t *tranp = ap->a_hba_tran;
+	int		(*func)(caddr_t);
+
+	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
+
+	if (in_pktp == NULL) {
+		int kf;
+
+		if (callback == SLEEP_FUNC)
+			kf = KM_SLEEP;
+		else
+			kf = KM_NOSLEEP;
+		pktw = kmem_cache_alloc(tranp->tran_pkt_cache_ptr,
+			    kf);
+		if (pktw == NULL)
+			goto fail1;
+
+		pktw->pcw_kmflags = 0;
+		in_pktp = &(pktw->pcw_pkt);
+		/*
+		 * target driver initializes pkt_comp, pkt_flags,
+		 * and pkt_time
+		 */
+		in_pktp->pkt_address = *ap;
+		in_pktp->pkt_resid = 0;
+		in_pktp->pkt_state = 0;
+		in_pktp->pkt_statistics = 0;
+		in_pktp->pkt_reason = 0;
+
+		in_pktp->pkt_cdblen = cmdlen;
+		if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_CDB) &&
+		    (cmdlen > DEFAULT_CDBLEN)) {
+			pktw->pcw_kmflags |= NEED_EXT_CDB;
+			in_pktp->pkt_cdbp = kmem_zalloc(cmdlen, kf);
+			if (in_pktp->pkt_cdbp == NULL)
+				goto fail2;
+		}
+		in_pktp->pkt_tgtlen = pplen;
+		if (pplen > DEFAULT_PRIVLEN) {
+			pktw->pcw_kmflags |= NEED_EXT_TGT;
+			in_pktp->pkt_private = kmem_zalloc(pplen, kf);
+			if (in_pktp->pkt_private == NULL)
+				goto fail3;
+		}
+		in_pktp->pkt_scblen = statuslen;
+		if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_SCB) &&
+		    (statuslen > DEFAULT_SCBLEN)) {
+			pktw->pcw_kmflags |= NEED_EXT_SCB;
+			in_pktp->pkt_scbp = kmem_zalloc(statuslen, kf);
+			if (in_pktp->pkt_scbp == NULL)
+				goto fail4;
+		}
+		if ((*tranp->tran_setup_pkt) (in_pktp,
+			func, NULL) == -1) {
+				goto fail5;
+		}
+	}
+	if (bp && bp->b_bcount) {
+		if ((*tranp->tran_setup_bp) (in_pktp, bp,
+		    flags, func, NULL) == -1) {
+			scsi_free_cache_pkt(ap, in_pktp);
+			in_pktp = NULL;
+		}
+	}
+	return (in_pktp);
+
+fail5:
+	if (pktw->pcw_kmflags & NEED_EXT_SCB) {
+		kmem_free(in_pktp->pkt_scbp, statuslen);
+		in_pktp->pkt_scbp = (opaque_t)((char *)in_pktp +
+		    tranp->tran_hba_len + DEFAULT_PRIVLEN +
+		    sizeof (struct scsi_pkt));
+		if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
+			in_pktp->pkt_scbp = (opaque_t)((in_pktp->pkt_scbp) +
+				DEFAULT_CDBLEN);
+		in_pktp->pkt_scblen = 0;
+	}
+fail4:
+	if (pktw->pcw_kmflags & NEED_EXT_TGT) {
+		kmem_free(in_pktp->pkt_private, pplen);
+		in_pktp->pkt_tgtlen = 0;
+		in_pktp->pkt_private = NULL;
+	}
+fail3:
+	if (pktw->pcw_kmflags & NEED_EXT_CDB) {
+		kmem_free(in_pktp->pkt_cdbp, cmdlen);
+		in_pktp->pkt_cdbp = (opaque_t)((char *)in_pktp +
+		    tranp->tran_hba_len +
+		    sizeof (struct scsi_pkt));
+		in_pktp->pkt_cdblen = 0;
+	}
+	pktw->pcw_kmflags &=
+	    ~(NEED_EXT_CDB|NEED_EXT_TGT|NEED_EXT_SCB);
+fail2:
+	kmem_cache_free(tranp->tran_pkt_cache_ptr, pktw);
+fail1:
+	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
+		ddi_set_callback(callback, callback_arg,
+			&scsi_callback_id);
+	}
+
+	return (NULL);
+}
+
+void
+scsi_free_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
+{
+	struct scsi_pkt_cache_wrapper *pktw;
+
+	(*A_TO_TRAN(ap)->tran_teardown_pkt)(pktp);
+	pktw = (struct scsi_pkt_cache_wrapper *)pktp;
+
+	/*
+	 * if we allocated memory for anything that wouldn't fit, free
+	 * the memory and restore the pointers
+	 */
+	if (pktw->pcw_kmflags & NEED_EXT_SCB) {
+		kmem_free(pktp->pkt_scbp, pktp->pkt_scblen);
+		pktp->pkt_scbp = (opaque_t)((char *)pktp +
+		    (A_TO_TRAN(ap))->tran_hba_len +
+		    DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper));
+		if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
+			pktp->pkt_scbp = (opaque_t)((pktp->pkt_scbp) +
+				DEFAULT_CDBLEN);
+		pktp->pkt_scblen = 0;
+	}
+	if (pktw->pcw_kmflags & NEED_EXT_TGT) {
+		kmem_free(pktp->pkt_private, pktp->pkt_tgtlen);
+		pktp->pkt_tgtlen = 0;
+		pktp->pkt_private = NULL;
+	}
+	if (pktw->pcw_kmflags & NEED_EXT_CDB) {
+		kmem_free(pktp->pkt_cdbp, pktp->pkt_cdblen);
+		pktp->pkt_cdbp = (opaque_t)((char *)pktp +
+		    (A_TO_TRAN(ap))->tran_hba_len +
+		    sizeof (struct scsi_pkt_cache_wrapper));
+		pktp->pkt_cdblen = 0;
+	}
+	pktw->pcw_kmflags &=
+	    ~(NEED_EXT_CDB|NEED_EXT_TGT|NEED_EXT_SCB);
+	ASSERT(pktw->pcw_kmflags == 0);
+	kmem_cache_free(A_TO_TRAN(ap)->tran_pkt_cache_ptr, pktw);
+
+	if (scsi_callback_id != 0) {
+		ddi_run_callback(&scsi_callback_id);
+	}
+
+}
+
 struct scsi_pkt *
 scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
     struct buf *bp, int cmdlen, int statuslen, int pplen,
--- a/usr/src/uts/common/sys/scsi/impl/transport.h	Mon Nov 28 11:50:15 2005 -0800
+++ b/usr/src/uts/common/sys/scsi/impl/transport.h	Mon Nov 28 12:14:38 2005 -0800
@@ -259,6 +259,31 @@
 	 * usr/src/uts/common/sys/scsi/impl/services.h
 	 */
 	int		tran_interconnect_type;
+	int		(*tran_pkt_constructor)(
+				struct scsi_pkt		*pkt,
+				scsi_hba_tran_t		*tran,
+				int			kmflag);
+	void		(*tran_pkt_destructor)(
+				struct scsi_pkt		*pkt,
+				scsi_hba_tran_t		*tran);
+	kmem_cache_t	*tran_pkt_cache_ptr;
+
+	uint_t		tran_hba_len;
+	int		(*tran_setup_pkt)(
+				struct scsi_pkt		*pkt,
+				int			(*callback)(
+								caddr_t	arg),
+				caddr_t			callback_arg);
+	int		(*tran_setup_bp)(
+				struct scsi_pkt		*pkt,
+				struct buf		*bp,
+				int			flags,
+				int			(*callback)(
+								caddr_t	arg),
+				caddr_t			callback_arg);
+	void		(*tran_teardown_pkt)(
+				struct scsi_pkt		*pkt);
+
 };
 
 #ifdef __lock_lint
@@ -379,6 +404,8 @@
 						/* structure per target */
 #define	SCSI_HBA_TRAN_ALLOC	0x02		/* set if scsi_hba_tran_alloc */
 						/* is called */
+#define	SCSI_HBA_TRAN_CDB	0x04		/* allocate cdb */
+#define	SCSI_HBA_TRAN_SCB	0x08		/* allocate sense */
 
 /*
  * Flags for scsi_hba allocation functions
--- a/usr/src/uts/common/sys/scsi/scsi_pkt.h	Mon Nov 28 11:50:15 2005 -0800
+++ b/usr/src/uts/common/sys/scsi/scsi_pkt.h	Mon Nov 28 12:14:38 2005 -0800
@@ -61,6 +61,9 @@
 	uint_t	pkt_state;		/* state of command */
 	uint_t	pkt_statistics;		/* statistics */
 	uchar_t	pkt_reason;		/* reason completion called */
+	uint_t	pkt_cdblen;
+	uint_t	pkt_tgtlen;
+	uint_t	pkt_scblen;
 };
 
 /*
@@ -116,7 +119,6 @@
  */
 #define	FLAG_NOQUEUE	0x80000000
 
-
 /*
  * Definitions for the pkt_reason field.
  */
--- a/usr/src/uts/common/sys/scsi/scsi_resource.h	Mon Nov 28 11:50:15 2005 -0800
+++ b/usr/src/uts/common/sys/scsi/scsi_resource.h	Mon Nov 28 12:14:38 2005 -0800
@@ -77,6 +77,25 @@
 void		scsi_resfree(struct scsi_pkt *);
 
 /*
+ * Private wrapper for scsi_pkt's allocated via scsi_init_cache_pkt()
+ */
+struct scsi_pkt_cache_wrapper {
+	struct scsi_pkt		pcw_pkt;
+	uint_t			pcw_kmflags;
+};
+
+#define	NEED_EXT_CDB	0x0001
+#define	NEED_EXT_TGT	0x0002
+#define	NEED_EXT_SCB	0x0004
+
+/*
+ * Private defines i.e. not part of the DDI.
+ */
+#define	DEFAULT_CDBLEN	16
+#define	DEFAULT_PRIVLEN	0
+#define	DEFAULT_SCBLEN	(sizeof (struct scsi_arq_status))
+
+/*
  * Preliminary version of the SCSA specification
  * mentioned a routine called scsi_pktfree, which
  * turned out to be semantically equivialent to