152130Smckusick /*
2*63207Sbostic * Copyright (c) 1992, 1993
3*63207Sbostic * The Regents of the University of California. All rights reserved.
452130Smckusick *
552130Smckusick * This code is derived from software contributed to Berkeley by
652130Smckusick * Ralph Campbell.
752130Smckusick *
852130Smckusick * %sccs.include.redist.c%
952130Smckusick *
10*63207Sbostic * @(#)scsi.c 8.1 (Berkeley) 06/10/93
1152130Smckusick */
1252130Smckusick
1352130Smckusick /*
1452130Smckusick * SCSI utility routines for making SCSI device drivers easier.
1552130Smckusick */
1652130Smckusick
1756522Sbostic #include <sys/param.h>
1852130Smckusick
1956525Sbostic #include <pmax/dev/device.h>
2056525Sbostic #include <pmax/dev/scsi.h>
2152130Smckusick
2252130Smckusick /*
2352130Smckusick * The error codes for class 0-6 sense data are class specific.
2452130Smckusick * The follow arrays of strings are used to print error messages.
2552130Smckusick */
2652130Smckusick static char *Class0Errors[] = {
2752130Smckusick "No sense data",
2852130Smckusick "No index signal",
2952130Smckusick "No seek complete",
3052130Smckusick "Write fault",
3152130Smckusick "Drive not ready",
3252130Smckusick "Drive not selected",
3352130Smckusick "No Track 00",
3452130Smckusick "Multiple drives selected",
3552130Smckusick "No address acknowledged",
3652130Smckusick "Media not loaded",
3752130Smckusick "Insufficient capacity",
3852130Smckusick "Drive timeout",
3952130Smckusick };
4052130Smckusick static char *Class1Errors[] = {
4152130Smckusick "ID CRC error",
4252130Smckusick "Unrecoverable data error",
4352130Smckusick "ID address mark not found",
4452130Smckusick "Data address mark not found",
4552130Smckusick "Record not found",
4652130Smckusick "Seek error",
4752130Smckusick "DMA timeout error",
4852130Smckusick "Write protected",
4952130Smckusick "Correctable data check",
5052130Smckusick "Bad block found",
5152130Smckusick "Interleave error",
5252130Smckusick "Data transfer incomplete",
5352130Smckusick "Unformatted or bad format on drive",
5452130Smckusick "Self test failed",
5552130Smckusick "Defective track (media errors)",
5652130Smckusick };
5752130Smckusick static char *Class2Errors[] = {
5852130Smckusick "Invalid command",
5952130Smckusick "Illegal block address",
6052130Smckusick "Aborted",
6152130Smckusick "Volume overflow",
6252130Smckusick };
6352130Smckusick static char *Class7Errors[] = {
6452130Smckusick "No sense data",
6552130Smckusick "Recoverable error",
6652130Smckusick "Drive not ready",
6752130Smckusick "Media error",
6852130Smckusick "Hardware error",
6952130Smckusick "Illegal request",
7052130Smckusick "Unit attention",
7152130Smckusick "Write protected",
7252130Smckusick "Blank check error",
7352130Smckusick "Vendor error",
7452130Smckusick "Powerup failure",
7552130Smckusick "Abort",
7652130Smckusick "Equal",
7752130Smckusick "Overflow",
7852130Smckusick "Reserved14/miscompare",
7952130Smckusick };
8052130Smckusick static int scsiNumErrors[] = {
8152130Smckusick sizeof(Class0Errors) / sizeof(char *),
8252130Smckusick sizeof(Class1Errors) / sizeof(char *),
8352130Smckusick sizeof(Class2Errors) / sizeof(char *),
8452130Smckusick 0, 0, 0, 0, 0,
8552130Smckusick };
8652130Smckusick static char **scsiErrors[] = {
8752130Smckusick Class0Errors,
8852130Smckusick Class1Errors,
8952130Smckusick Class2Errors,
9052130Smckusick };
9152130Smckusick
9252130Smckusick /*
9352130Smckusick * Decode the sense data and print a suitable message.
9452130Smckusick */
scsiPrintSense(sp,len)9552130Smckusick scsiPrintSense(sp, len)
9652130Smckusick register ScsiClass7Sense *sp;
9752130Smckusick int len;
9852130Smckusick {
9952130Smckusick ScsiClass0Sense *sp0;
10052130Smckusick int class, code;
10152130Smckusick
10252130Smckusick if (sp->error7 != 0x70) {
10352130Smckusick sp0 = (ScsiClass0Sense *)sp;
10452130Smckusick class = sp0->error >> 4;
10552130Smckusick code = sp0->error & 0xF;
10652130Smckusick if (code >= scsiNumErrors[class])
10752130Smckusick printf("sense error 0x%x", sp0->error);
10852130Smckusick else
10952130Smckusick printf("%s", scsiErrors[class][code]);
11052130Smckusick if (sp->valid)
11152130Smckusick printf(", blk %d", (sp0->highAddr << 16) |
11252130Smckusick (sp0->midAddr << 8) | sp0->lowAddr);
11352130Smckusick } else {
11452130Smckusick if (sp->key >= sizeof(Class7Errors) / sizeof(char *))
11552130Smckusick printf("sense class 7 error 0x%x", sp->key);
11652130Smckusick else
11752130Smckusick printf("%s", Class7Errors[sp->key]);
11853082Sralph if (sp->fileMark)
11953082Sralph printf(", file mark seen");
12053082Sralph if (sp->endOfMedia)
12153082Sralph printf(", end of media seen");
12253082Sralph if (sp->badBlockLen)
12353082Sralph printf(", block length mis-match");
12452130Smckusick if (sp->valid)
12552130Smckusick printf(", blk %d", (sp->info1 << 24) |
12652130Smckusick (sp->info2 << 16) | (sp->info3 << 8) |
12752130Smckusick sp->info4);
12852130Smckusick }
12952130Smckusick printf("\n");
13052130Smckusick }
13152130Smckusick
13252130Smckusick /*
13352130Smckusick * Setup a command block for a SCSI Group0 command.
13452130Smckusick */
13552130Smckusick void
scsiGroup0Cmd(cmd,lun,block,count,c)13652130Smckusick scsiGroup0Cmd(cmd, lun, block, count, c)
13752130Smckusick unsigned cmd; /* group0 SCSI command */
13852130Smckusick unsigned lun; /* Logical Unit Number */
13952130Smckusick register unsigned block; /* starting block number for transfer */
14052130Smckusick unsigned count; /* # of sectors/bytes to transfer */
14152130Smckusick register ScsiGroup0Cmd *c; /* command to be filled in */
14252130Smckusick {
14352130Smckusick
14452130Smckusick c->command = cmd;
14552130Smckusick c->unitNumber = lun;
14652130Smckusick c->highAddr = block >> 16;
14752130Smckusick c->midAddr = block >> 8;
14852130Smckusick c->lowAddr = block;
14952130Smckusick c->blockCount = count;
15052130Smckusick c->control = 0;
15152130Smckusick }
15252130Smckusick
15352130Smckusick /*
15452130Smckusick * Setup a command block for a SCSI Group1 command.
15552130Smckusick */
15652130Smckusick void
scsiGroup1Cmd(cmd,lun,block,count,c)15752130Smckusick scsiGroup1Cmd(cmd, lun, block, count, c)
15852130Smckusick unsigned cmd; /* group0 SCSI command */
15952130Smckusick unsigned lun; /* Logical Unit Number */
16052130Smckusick register unsigned block; /* starting block number for transfer */
16152130Smckusick unsigned count; /* # of sectors/bytes to transfer */
16252130Smckusick register ScsiGroup1Cmd *c; /* command to be filled in */
16352130Smckusick {
16452130Smckusick
16552130Smckusick c->command = cmd;
16652130Smckusick c->unitNumber = lun;
16752130Smckusick c->pad1 = 0;
16852130Smckusick c->highAddr = block >> 24;
16952130Smckusick c->midHighAddr = block >> 16;
17052130Smckusick c->midLowAddr = block >> 8;
17152130Smckusick c->lowAddr = block;
17252130Smckusick c->pad2 = 0;
17352130Smckusick c->highBlockCount = count >> 8;
17452130Smckusick c->lowBlockCount = count;
17552130Smckusick c->control = 0;
17652130Smckusick }
177