Mercurial > illumos > illumos-gate
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