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