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