xref: /illumos-gate/usr/src/uts/intel/io/dktp/dcdev/gda.c (revision 7b93957c241820af312fd1aad1e23e305a8dabbf)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/scsi/scsi.h>
30 
31 #include <sys/dktp/dadev.h>
32 #include <sys/dktp/gda.h>
33 
34 /*
35  *	Generic Direct Attached Device
36  */
37 
38 static char *gda_name(uchar_t cmd, char **cmdvec);
39 
40 #ifdef	GDA_DEBUG
41 #define	DENT	0x0001
42 #define	DPKT	0x0002
43 #define	DERR	0x0004
44 static	int	gda_debug = DERR|DENT|DPKT;
45 
46 #endif	/* GDA_DEBUG */
47 
48 /*
49  * Local static data
50  */
51 
52 /*
53  *	global data
54  */
55 
56 /*
57  *	This is the loadable module wrapper
58  */
59 #include <sys/modctl.h>
60 
61 extern struct mod_ops mod_miscops;
62 
63 static struct modlmisc modlmisc = {
64 	&mod_miscops,	/* Type of module */
65 	"Generic Direct Attached Device Utilities"
66 };
67 
68 static struct modlinkage modlinkage = {
69 	MODREV_1, (void *)&modlmisc, NULL
70 };
71 
72 int
73 _init(void)
74 {
75 	return (mod_install(&modlinkage));
76 }
77 
78 int
79 _fini(void)
80 {
81 #ifdef GDA_DEBUG
82 	if (gda_debug & DENT)
83 		PRF("gda_fini: call\n");
84 #endif
85 	return (mod_remove(&modlinkage));
86 }
87 
88 int
89 _info(struct modinfo *modinfop)
90 {
91 	return (mod_info(&modlinkage, modinfop));
92 }
93 
94 
95 void
96 gda_inqfill(char *p, int l, char *s)
97 {
98 	register unsigned i = 0, c;
99 
100 	if (!p)
101 		return;
102 	while (i++ < l) {
103 /* 		clean strings of non-printing chars			*/
104 		if ((c = *p++) < ' ' || c > 0176) {
105 			c = ' ';
106 		}
107 		*s++ = (char)c;
108 	}
109 	*s++ = 0;
110 }
111 
112 static char *
113 gda_name(uchar_t cmd, char **cmdvec)
114 {
115 	while (*cmdvec != NULL) {
116 		if (cmd == **cmdvec) {
117 			return (*cmdvec + 1);
118 		}
119 		cmdvec++;
120 	}
121 	return ("<undecoded cmd>");
122 }
123 
124 
125 struct cmpkt *
126 gda_pktprep(opaque_t objp, struct cmpkt *in_pktp, opaque_t dmatoken,
127 	int (*callback)(caddr_t), caddr_t arg)
128 {
129 	register struct	cmpkt *pktp;
130 	register struct	buf *bp = (struct buf *)dmatoken;
131 
132 	if (in_pktp) {
133 		pktp = in_pktp;
134 	} else {
135 		pktp = CTL_PKTALLOC(objp, callback, arg);
136 		if (pktp == NULL)
137 			return (NULL);
138 	}
139 
140 	if (bp) {
141 		if (bp->b_bcount) {
142 			if (CTL_MEMSETUP(objp, pktp, bp, callback, arg) ==
143 			    NULL) {
144 				if (!in_pktp)
145 					CTL_PKTFREE(objp, pktp);
146 				return (NULL);
147 			}
148 		}
149 		bp->av_back = (struct buf *)pktp;
150 		pktp->cp_bp = bp;
151 	}
152 	pktp->cp_retry = 0;
153 	pktp->cp_objp  = objp;
154 
155 
156 #ifdef GDA_DEBUG
157 	if (gda_debug & DPKT)
158 		PRF("gda_pktprep: pktp=0x%x \n", pktp);
159 #endif
160 	return (pktp);
161 }
162 
163 void
164 gda_free(opaque_t objp, struct cmpkt *pktp, struct buf *bp)
165 {
166 	if (pktp) {
167 		CTL_MEMFREE(objp, pktp);
168 		CTL_PKTFREE(objp, pktp);
169 	}
170 
171 	if (bp) {
172 		if (bp->b_un.b_addr)
173 			i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
174 		freerbuf(bp);
175 	}
176 }
177 
178 void
179 gda_log(dev_info_t *dev, char *label, uint_t level, const char *fmt, ...)
180 {
181 	auto char name[256];
182 	auto char buf [256];
183 	va_list ap;
184 	int log_only = 0;
185 	int boot_only = 0;
186 	int console_only = 0;
187 
188 	switch (*fmt) {
189 	case '!':
190 		log_only = 1;
191 		fmt++;
192 		break;
193 	case '?':
194 		boot_only = 1;
195 		fmt++;
196 		break;
197 	case '^':
198 		console_only = 1;
199 		fmt++;
200 		break;
201 	}
202 
203 
204 	if (dev) {
205 		if (level == CE_PANIC || level == CE_WARN) {
206 			(void) sprintf(name, "%s (%s%d):\n",
207 				ddi_pathname(dev, buf), label,
208 				ddi_get_instance(dev));
209 		} else if (level == CE_NOTE ||
210 		    level >= (uint_t)SCSI_DEBUG) {
211 			(void) sprintf(name,
212 			    "%s%d:", label, ddi_get_instance(dev));
213 		} else if (level == CE_CONT) {
214 			name[0] = '\0';
215 		}
216 	} else {
217 		(void) sprintf(name, "%s:", label);
218 	}
219 
220 	va_start(ap, fmt);
221 	(void) vsprintf(buf, fmt, ap);
222 	va_end(ap);
223 
224 	switch (level) {
225 		case CE_NOTE:
226 			level = CE_CONT;
227 			/* FALLTHROUGH */
228 		case CE_CONT:
229 		case CE_WARN:
230 		case CE_PANIC:
231 			if (boot_only) {
232 				cmn_err(level, "?%s\t%s", name, buf);
233 			} else if (console_only) {
234 				cmn_err(level, "^%s\t%s", name, buf);
235 			} else if (log_only) {
236 				cmn_err(level, "!%s\t%s", name, buf);
237 			} else {
238 				cmn_err(level, "%s\t%s", name, buf);
239 			}
240 			break;
241 		default:
242 			cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, buf);
243 			break;
244 	}
245 }
246 
247 void
248 gda_errmsg(struct scsi_device *devp, struct cmpkt *pktp, char *label,
249     int severity, int blkno, int err_blkno,
250     char **cmdvec, char **senvec)
251 {
252 	auto char buf[256];
253 	dev_info_t *dev = devp->sd_dev;
254 	static char *error_classes[] = {
255 		"All", "Unknown", "Informational",
256 		"Recovered", "Retryable", "Fatal"
257 	};
258 
259 	bzero((caddr_t)buf, 256);
260 	(void) sprintf(buf, "Error for command '%s'\tError Level: %s",
261 		gda_name(*(uchar_t *)pktp->cp_cdbp, cmdvec),
262 		error_classes[severity]);
263 	gda_log(dev, label, CE_WARN, buf);
264 
265 	bzero((caddr_t)buf, 256);
266 	if ((blkno != -1) && (err_blkno != -1)) {
267 		(void) sprintf(buf, "Requested Block %d, Error Block: %d\n",
268 		    blkno, err_blkno);
269 		gda_log(dev, label, CE_CONT, buf);
270 	}
271 
272 	bzero((caddr_t)buf, 256);
273 	(void) sprintf(buf, "Sense Key: %s\n",
274 		gda_name(*(uchar_t *)pktp->cp_scbp, senvec));
275 
276 	gda_log(dev, label, CE_CONT, buf);
277 	bzero((caddr_t)buf, 256);
278 	(void) strcpy(buf, "Vendor '");
279 	gda_inqfill(devp->sd_inq->inq_vid, 8, &buf[strlen(buf)]);
280 	(void) sprintf(&buf[strlen(buf)],
281 		"' error code: 0x%x",
282 		*(uchar_t *)pktp->cp_scbp);
283 	gda_log(dev, label, CE_CONT, "%s\n", buf);
284 }
285