11709Smlf /*
21709Smlf * CDDL HEADER START
31709Smlf *
41709Smlf * The contents of this file are subject to the terms of the
51709Smlf * Common Development and Distribution License (the "License").
61709Smlf * You may not use this file except in compliance with the License.
71709Smlf *
81709Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91709Smlf * or http://www.opensolaris.org/os/licensing.
101709Smlf * See the License for the specific language governing permissions
111709Smlf * and limitations under the License.
121709Smlf *
131709Smlf * When distributing Covered Code, include this CDDL HEADER in each
141709Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151709Smlf * If applicable, add the following below this CDDL HEADER, with the
161709Smlf * fields enclosed by brackets "[]" replaced with your own identifying
171709Smlf * information: Portions Copyright [yyyy] [name of copyright owner]
181709Smlf *
191709Smlf * CDDL HEADER END
201709Smlf */
211709Smlf
221709Smlf /*
23*7563SPrasad.Singamsetty@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
241709Smlf * Use is subject to license terms.
251709Smlf */
261709Smlf
271709Smlf #include <sys/scsi/scsi.h>
281709Smlf
291709Smlf #include <sys/dktp/dadev.h>
301709Smlf #include <sys/dktp/gda.h>
311709Smlf
321709Smlf /*
331709Smlf * Generic Direct Attached Device
341709Smlf */
351709Smlf
361709Smlf static char *gda_name(uchar_t cmd, char **cmdvec);
371709Smlf
381709Smlf #ifdef GDA_DEBUG
391709Smlf #define DENT 0x0001
401709Smlf #define DPKT 0x0002
411709Smlf #define DERR 0x0004
421709Smlf static int gda_debug = DERR|DENT|DPKT;
431709Smlf
441709Smlf #endif /* GDA_DEBUG */
451709Smlf
461709Smlf /*
471709Smlf * Local static data
481709Smlf */
491709Smlf
501709Smlf /*
511709Smlf * global data
521709Smlf */
531709Smlf
541709Smlf /*
551709Smlf * This is the loadable module wrapper
561709Smlf */
571709Smlf #include <sys/modctl.h>
581709Smlf
591709Smlf extern struct mod_ops mod_miscops;
601709Smlf
611709Smlf static struct modlmisc modlmisc = {
621709Smlf &mod_miscops, /* Type of module */
631709Smlf "Generic Direct Attached Device Utilities"
641709Smlf };
651709Smlf
661709Smlf static struct modlinkage modlinkage = {
671709Smlf MODREV_1, (void *)&modlmisc, NULL
681709Smlf };
691709Smlf
701709Smlf int
_init(void)711709Smlf _init(void)
721709Smlf {
731709Smlf return (mod_install(&modlinkage));
741709Smlf }
751709Smlf
761709Smlf int
_fini(void)771709Smlf _fini(void)
781709Smlf {
791709Smlf #ifdef GDA_DEBUG
801709Smlf if (gda_debug & DENT)
811709Smlf PRF("gda_fini: call\n");
821709Smlf #endif
831709Smlf return (mod_remove(&modlinkage));
841709Smlf }
851709Smlf
861709Smlf int
_info(struct modinfo * modinfop)871709Smlf _info(struct modinfo *modinfop)
881709Smlf {
891709Smlf return (mod_info(&modlinkage, modinfop));
901709Smlf }
911709Smlf
921709Smlf
931709Smlf void
gda_inqfill(char * p,int l,char * s)941709Smlf gda_inqfill(char *p, int l, char *s)
951709Smlf {
961709Smlf register unsigned i = 0, c;
971709Smlf
981709Smlf if (!p)
991709Smlf return;
1001709Smlf while (i++ < l) {
1011709Smlf /* clean strings of non-printing chars */
1021709Smlf if ((c = *p++) < ' ' || c > 0176) {
1031709Smlf c = ' ';
1041709Smlf }
1051709Smlf *s++ = (char)c;
1061709Smlf }
1071709Smlf *s++ = 0;
1081709Smlf }
1091709Smlf
1101709Smlf static char *
gda_name(uchar_t cmd,char ** cmdvec)1111709Smlf gda_name(uchar_t cmd, char **cmdvec)
1121709Smlf {
1131709Smlf while (*cmdvec != NULL) {
1141709Smlf if (cmd == **cmdvec) {
1151709Smlf return (*cmdvec + 1);
1161709Smlf }
1171709Smlf cmdvec++;
1181709Smlf }
1191709Smlf return ("<undecoded cmd>");
1201709Smlf }
1211709Smlf
1221709Smlf
1231709Smlf struct cmpkt *
gda_pktprep(opaque_t objp,struct cmpkt * in_pktp,opaque_t dmatoken,int (* callback)(caddr_t),caddr_t arg)1241709Smlf gda_pktprep(opaque_t objp, struct cmpkt *in_pktp, opaque_t dmatoken,
1251709Smlf int (*callback)(caddr_t), caddr_t arg)
1261709Smlf {
1271709Smlf register struct cmpkt *pktp;
1281709Smlf register struct buf *bp = (struct buf *)dmatoken;
1291709Smlf
1301709Smlf if (in_pktp) {
1311709Smlf pktp = in_pktp;
1321709Smlf } else {
1331709Smlf pktp = CTL_PKTALLOC(objp, callback, arg);
1341709Smlf if (pktp == NULL)
1351709Smlf return (NULL);
1361709Smlf }
1371709Smlf
1381709Smlf if (bp) {
1391709Smlf if (bp->b_bcount) {
1401709Smlf if (CTL_MEMSETUP(objp, pktp, bp, callback, arg) ==
1411709Smlf NULL) {
1421709Smlf if (!in_pktp)
1431709Smlf CTL_PKTFREE(objp, pktp);
1441709Smlf return (NULL);
1451709Smlf }
1461709Smlf }
1471709Smlf bp->av_back = (struct buf *)pktp;
1481709Smlf pktp->cp_bp = bp;
1491709Smlf }
1501709Smlf pktp->cp_retry = 0;
1511709Smlf pktp->cp_objp = objp;
1521709Smlf
1531709Smlf
1541709Smlf #ifdef GDA_DEBUG
1551709Smlf if (gda_debug & DPKT)
1561709Smlf PRF("gda_pktprep: pktp=0x%x \n", pktp);
1571709Smlf #endif
1581709Smlf return (pktp);
1591709Smlf }
1601709Smlf
1611709Smlf void
gda_free(opaque_t objp,struct cmpkt * pktp,struct buf * bp)1621709Smlf gda_free(opaque_t objp, struct cmpkt *pktp, struct buf *bp)
1631709Smlf {
1641709Smlf if (pktp) {
1651709Smlf CTL_MEMFREE(objp, pktp);
1661709Smlf CTL_PKTFREE(objp, pktp);
1671709Smlf }
1681709Smlf
1691709Smlf if (bp) {
1701709Smlf if (bp->b_un.b_addr)
1711900Seota i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
1721709Smlf freerbuf(bp);
1731709Smlf }
1741709Smlf }
1751709Smlf
1761709Smlf void
gda_log(dev_info_t * dev,char * label,uint_t level,const char * fmt,...)1771709Smlf gda_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...)
1781709Smlf {
1791709Smlf auto char name[256];
1801709Smlf auto char buf [256];
1811709Smlf va_list ap;
1821709Smlf int log_only = 0;
1831709Smlf int boot_only = 0;
1841709Smlf int console_only = 0;
1851709Smlf
1861709Smlf switch (*fmt) {
1871709Smlf case '!':
1881709Smlf log_only = 1;
1891709Smlf fmt++;
1901709Smlf break;
1911709Smlf case '?':
1921709Smlf boot_only = 1;
1931709Smlf fmt++;
1941709Smlf break;
1951709Smlf case '^':
1961709Smlf console_only = 1;
1971709Smlf fmt++;
1981709Smlf break;
1991709Smlf }
2001709Smlf
2011709Smlf
2021709Smlf if (dev) {
2031709Smlf if (level == CE_PANIC || level == CE_WARN) {
2041709Smlf (void) sprintf(name, "%s (%s%d):\n",
205*7563SPrasad.Singamsetty@Sun.COM ddi_pathname(dev, buf), label,
206*7563SPrasad.Singamsetty@Sun.COM ddi_get_instance(dev));
2071709Smlf } else if (level == CE_NOTE ||
2081709Smlf level >= (uint_t)SCSI_DEBUG) {
2091709Smlf (void) sprintf(name,
2101709Smlf "%s%d:", label, ddi_get_instance(dev));
2111709Smlf } else if (level == CE_CONT) {
2121709Smlf name[0] = '\0';
2131709Smlf }
2141709Smlf } else {
2151709Smlf (void) sprintf(name, "%s:", label);
2161709Smlf }
2171709Smlf
2181709Smlf va_start(ap, fmt);
2191709Smlf (void) vsprintf(buf, fmt, ap);
2201709Smlf va_end(ap);
2211709Smlf
2221709Smlf switch (level) {
2231709Smlf case CE_NOTE:
2241709Smlf level = CE_CONT;
2251709Smlf /* FALLTHROUGH */
2261709Smlf case CE_CONT:
2271709Smlf case CE_WARN:
2281709Smlf case CE_PANIC:
2291709Smlf if (boot_only) {
2301709Smlf cmn_err(level, "?%s\t%s", name, buf);
2311709Smlf } else if (console_only) {
2321709Smlf cmn_err(level, "^%s\t%s", name, buf);
2331709Smlf } else if (log_only) {
2341709Smlf cmn_err(level, "!%s\t%s", name, buf);
2351709Smlf } else {
2361709Smlf cmn_err(level, "%s\t%s", name, buf);
2371709Smlf }
2381709Smlf break;
2391709Smlf default:
2401709Smlf cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, buf);
2411709Smlf break;
2421709Smlf }
2431709Smlf }
2441709Smlf
2451709Smlf void
gda_errmsg(struct scsi_device * devp,struct cmpkt * pktp,char * label,int severity,daddr_t blkno,daddr_t err_blkno,char ** cmdvec,char ** senvec)2461709Smlf gda_errmsg(struct scsi_device *devp, struct cmpkt *pktp, char *label,
247*7563SPrasad.Singamsetty@Sun.COM int severity, daddr_t blkno, daddr_t err_blkno,
2481709Smlf char **cmdvec, char **senvec)
2491709Smlf {
2501709Smlf auto char buf[256];
2511709Smlf dev_info_t *dev = devp->sd_dev;
2521709Smlf static char *error_classes[] = {
2531709Smlf "All", "Unknown", "Informational",
2541709Smlf "Recovered", "Retryable", "Fatal"
2551709Smlf };
2561709Smlf
2571709Smlf bzero((caddr_t)buf, 256);
2581709Smlf (void) sprintf(buf, "Error for command '%s'\tError Level: %s",
259*7563SPrasad.Singamsetty@Sun.COM gda_name(*(uchar_t *)pktp->cp_cdbp, cmdvec),
260*7563SPrasad.Singamsetty@Sun.COM error_classes[severity]);
2611709Smlf gda_log(dev, label, CE_WARN, buf);
2621709Smlf
2631709Smlf bzero((caddr_t)buf, 256);
2641709Smlf if ((blkno != -1) && (err_blkno != -1)) {
265*7563SPrasad.Singamsetty@Sun.COM (void) sprintf(buf, "Requested Block %ld, Error Block: %ld\n",
2661709Smlf blkno, err_blkno);
2671709Smlf gda_log(dev, label, CE_CONT, buf);
2681709Smlf }
2691709Smlf
2701709Smlf bzero((caddr_t)buf, 256);
2711709Smlf (void) sprintf(buf, "Sense Key: %s\n",
272*7563SPrasad.Singamsetty@Sun.COM gda_name(*(uchar_t *)pktp->cp_scbp, senvec));
2731709Smlf
2741709Smlf gda_log(dev, label, CE_CONT, buf);
2751709Smlf bzero((caddr_t)buf, 256);
2761709Smlf (void) strcpy(buf, "Vendor '");
2771709Smlf gda_inqfill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]);
2781709Smlf (void) sprintf(&buf[strlen(buf)],
279*7563SPrasad.Singamsetty@Sun.COM "' error code: 0x%x",
280*7563SPrasad.Singamsetty@Sun.COM *(uchar_t *)pktp->cp_scbp);
2811709Smlf gda_log(dev, label, CE_CONT, "%s\n", buf);
2821709Smlf }
283