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 }