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