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 71 _init(void) 72 { 73 return (mod_install(&modlinkage)); 74 } 75 76 int 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 87 _info(struct modinfo *modinfop) 88 { 89 return (mod_info(&modlinkage, modinfop)); 90 } 91 92 93 void 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 * 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 * 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 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 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 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 }