1*52130Smckusick /* 2*52130Smckusick * Copyright (c) 1992 Regents of the University of California. 3*52130Smckusick * All rights reserved. 4*52130Smckusick * 5*52130Smckusick * This code is derived from software contributed to Berkeley by 6*52130Smckusick * Ralph Campbell. 7*52130Smckusick * 8*52130Smckusick * %sccs.include.redist.c% 9*52130Smckusick * 10*52130Smckusick * @(#)scsi.c 7.1 (Berkeley) 01/07/92 11*52130Smckusick */ 12*52130Smckusick 13*52130Smckusick /* 14*52130Smckusick * SCSI utility routines for making SCSI device drivers easier. 15*52130Smckusick */ 16*52130Smckusick 17*52130Smckusick #include "param.h" 18*52130Smckusick 19*52130Smckusick #include "device.h" 20*52130Smckusick #include "scsi.h" 21*52130Smckusick 22*52130Smckusick /* 23*52130Smckusick * The error codes for class 0-6 sense data are class specific. 24*52130Smckusick * The follow arrays of strings are used to print error messages. 25*52130Smckusick */ 26*52130Smckusick static char *Class0Errors[] = { 27*52130Smckusick "No sense data", 28*52130Smckusick "No index signal", 29*52130Smckusick "No seek complete", 30*52130Smckusick "Write fault", 31*52130Smckusick "Drive not ready", 32*52130Smckusick "Drive not selected", 33*52130Smckusick "No Track 00", 34*52130Smckusick "Multiple drives selected", 35*52130Smckusick "No address acknowledged", 36*52130Smckusick "Media not loaded", 37*52130Smckusick "Insufficient capacity", 38*52130Smckusick "Drive timeout", 39*52130Smckusick }; 40*52130Smckusick static char *Class1Errors[] = { 41*52130Smckusick "ID CRC error", 42*52130Smckusick "Unrecoverable data error", 43*52130Smckusick "ID address mark not found", 44*52130Smckusick "Data address mark not found", 45*52130Smckusick "Record not found", 46*52130Smckusick "Seek error", 47*52130Smckusick "DMA timeout error", 48*52130Smckusick "Write protected", 49*52130Smckusick "Correctable data check", 50*52130Smckusick "Bad block found", 51*52130Smckusick "Interleave error", 52*52130Smckusick "Data transfer incomplete", 53*52130Smckusick "Unformatted or bad format on drive", 54*52130Smckusick "Self test failed", 55*52130Smckusick "Defective track (media errors)", 56*52130Smckusick }; 57*52130Smckusick static char *Class2Errors[] = { 58*52130Smckusick "Invalid command", 59*52130Smckusick "Illegal block address", 60*52130Smckusick "Aborted", 61*52130Smckusick "Volume overflow", 62*52130Smckusick }; 63*52130Smckusick static char *Class7Errors[] = { 64*52130Smckusick "No sense data", 65*52130Smckusick "Recoverable error", 66*52130Smckusick "Drive not ready", 67*52130Smckusick "Media error", 68*52130Smckusick "Hardware error", 69*52130Smckusick "Illegal request", 70*52130Smckusick "Unit attention", 71*52130Smckusick "Write protected", 72*52130Smckusick "Blank check error", 73*52130Smckusick "Vendor error", 74*52130Smckusick "Powerup failure", 75*52130Smckusick "Abort", 76*52130Smckusick "Equal", 77*52130Smckusick "Overflow", 78*52130Smckusick "Reserved14/miscompare", 79*52130Smckusick }; 80*52130Smckusick static int scsiNumErrors[] = { 81*52130Smckusick sizeof(Class0Errors) / sizeof(char *), 82*52130Smckusick sizeof(Class1Errors) / sizeof(char *), 83*52130Smckusick sizeof(Class2Errors) / sizeof(char *), 84*52130Smckusick 0, 0, 0, 0, 0, 85*52130Smckusick }; 86*52130Smckusick static char **scsiErrors[] = { 87*52130Smckusick Class0Errors, 88*52130Smckusick Class1Errors, 89*52130Smckusick Class2Errors, 90*52130Smckusick }; 91*52130Smckusick 92*52130Smckusick /* 93*52130Smckusick * Decode the sense data and print a suitable message. 94*52130Smckusick */ 95*52130Smckusick scsiPrintSense(sp, len) 96*52130Smckusick register ScsiClass7Sense *sp; 97*52130Smckusick int len; 98*52130Smckusick { 99*52130Smckusick ScsiClass0Sense *sp0; 100*52130Smckusick int class, code; 101*52130Smckusick 102*52130Smckusick if (sp->error7 != 0x70) { 103*52130Smckusick sp0 = (ScsiClass0Sense *)sp; 104*52130Smckusick class = sp0->error >> 4; 105*52130Smckusick code = sp0->error & 0xF; 106*52130Smckusick if (code >= scsiNumErrors[class]) 107*52130Smckusick printf("sense error 0x%x", sp0->error); 108*52130Smckusick else 109*52130Smckusick printf("%s", scsiErrors[class][code]); 110*52130Smckusick if (sp->valid) 111*52130Smckusick printf(", blk %d", (sp0->highAddr << 16) | 112*52130Smckusick (sp0->midAddr << 8) | sp0->lowAddr); 113*52130Smckusick } else { 114*52130Smckusick if (sp->key >= sizeof(Class7Errors) / sizeof(char *)) 115*52130Smckusick printf("sense class 7 error 0x%x", sp->key); 116*52130Smckusick else 117*52130Smckusick printf("%s", Class7Errors[sp->key]); 118*52130Smckusick if (sp->valid) 119*52130Smckusick printf(", blk %d", (sp->info1 << 24) | 120*52130Smckusick (sp->info2 << 16) | (sp->info3 << 8) | 121*52130Smckusick sp->info4); 122*52130Smckusick } 123*52130Smckusick printf("\n"); 124*52130Smckusick } 125*52130Smckusick 126*52130Smckusick /* 127*52130Smckusick * Setup a command block for a SCSI Group0 command. 128*52130Smckusick */ 129*52130Smckusick void 130*52130Smckusick scsiGroup0Cmd(cmd, lun, block, count, c) 131*52130Smckusick unsigned cmd; /* group0 SCSI command */ 132*52130Smckusick unsigned lun; /* Logical Unit Number */ 133*52130Smckusick register unsigned block; /* starting block number for transfer */ 134*52130Smckusick unsigned count; /* # of sectors/bytes to transfer */ 135*52130Smckusick register ScsiGroup0Cmd *c; /* command to be filled in */ 136*52130Smckusick { 137*52130Smckusick 138*52130Smckusick c->command = cmd; 139*52130Smckusick c->unitNumber = lun; 140*52130Smckusick c->highAddr = block >> 16; 141*52130Smckusick c->midAddr = block >> 8; 142*52130Smckusick c->lowAddr = block; 143*52130Smckusick c->blockCount = count; 144*52130Smckusick c->control = 0; 145*52130Smckusick } 146*52130Smckusick 147*52130Smckusick /* 148*52130Smckusick * Setup a command block for a SCSI Group1 command. 149*52130Smckusick */ 150*52130Smckusick void 151*52130Smckusick scsiGroup1Cmd(cmd, lun, block, count, c) 152*52130Smckusick unsigned cmd; /* group0 SCSI command */ 153*52130Smckusick unsigned lun; /* Logical Unit Number */ 154*52130Smckusick register unsigned block; /* starting block number for transfer */ 155*52130Smckusick unsigned count; /* # of sectors/bytes to transfer */ 156*52130Smckusick register ScsiGroup1Cmd *c; /* command to be filled in */ 157*52130Smckusick { 158*52130Smckusick 159*52130Smckusick c->command = cmd; 160*52130Smckusick c->unitNumber = lun; 161*52130Smckusick c->pad1 = 0; 162*52130Smckusick c->highAddr = block >> 24; 163*52130Smckusick c->midHighAddr = block >> 16; 164*52130Smckusick c->midLowAddr = block >> 8; 165*52130Smckusick c->lowAddr = block; 166*52130Smckusick c->pad2 = 0; 167*52130Smckusick c->highBlockCount = count >> 8; 168*52130Smckusick c->lowBlockCount = count; 169*52130Smckusick c->control = 0; 170*52130Smckusick } 171