1560 lines
38 KiB
C
1560 lines
38 KiB
C
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)startup.c 1.1 94/10/31";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1991 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* This file contains the code to perform program startup. This
|
|
* includes reading the data file and the search for disks.
|
|
*/
|
|
#include "global.h"
|
|
#include <sys/fcntl.h>
|
|
#include "startup.h"
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <scsi/generic/mode.h>
|
|
#include <scsi/generic/sense.h>
|
|
#include <scsi/generic/commands.h>
|
|
#include <scsi/generic/dad_mode.h>
|
|
#include <scsi/impl/mode.h>
|
|
#include <scsi/impl/uscsi.h>
|
|
#include <scsi/impl/commands.h>
|
|
|
|
|
|
extern struct ctlr_type ctlr_types[];
|
|
extern int nctypes;
|
|
extern char * strchr();
|
|
|
|
char **search_path;
|
|
|
|
struct chg_list *new_chg_list();
|
|
|
|
|
|
/*
|
|
* This global is used to store the current line # in the data file.
|
|
* It must be global because the I/O routines are allowed to side
|
|
* effect it to keep track of backslashed newlines.
|
|
*/
|
|
int data_lineno; /* current line # in data file */
|
|
|
|
/*
|
|
* This routine digests the options on the command line. It returns
|
|
* the index into argv of the first string that is not an option. If
|
|
* there are none, it returns -1.
|
|
*/
|
|
int
|
|
do_options(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
register char *ptr;
|
|
register int i, next;
|
|
|
|
/*
|
|
* Default is no extended messages. Can be enabled manually.
|
|
*/
|
|
option_msg = 0;
|
|
|
|
/*
|
|
* Loop through the argument list, incrementing each time by
|
|
* an amount determined by the options found.
|
|
*/
|
|
for (i = 1; i < argc; i = next) {
|
|
/*
|
|
* Start out assuming an increment of 1.
|
|
*/
|
|
next = i + 1;
|
|
/*
|
|
* As soon as we hit a non-option, we're done.
|
|
*/
|
|
if (*argv[i] != '-')
|
|
return (i);
|
|
/*
|
|
* Loop through all the characters in this option string.
|
|
*/
|
|
for (ptr = argv[i] + 1; *ptr != '\0'; ptr++) {
|
|
/*
|
|
* Determine each option represented. For options
|
|
* that use a second string, increase the increment
|
|
* of the main loop so they aren't re-interpreted.
|
|
*/
|
|
switch (*ptr) {
|
|
case 's':
|
|
case 'S':
|
|
option_s = 1;
|
|
break;
|
|
case 'f':
|
|
case 'F':
|
|
option_f = argv[next++];
|
|
if (next > argc)
|
|
goto badopt;
|
|
break;
|
|
case 'l':
|
|
case 'L':
|
|
option_l = argv[next++];
|
|
if (next > argc)
|
|
goto badopt;
|
|
break;
|
|
case 'x':
|
|
case 'X':
|
|
option_x = argv[next++];
|
|
if (next > argc)
|
|
goto badopt;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
option_d = argv[next++];
|
|
if (next > argc)
|
|
goto badopt;
|
|
break;
|
|
case 't':
|
|
case 'T':
|
|
option_t = argv[next++];
|
|
if (next > argc)
|
|
goto badopt;
|
|
break;
|
|
case 'p':
|
|
case 'P':
|
|
option_p = argv[next++];
|
|
if (next > argc)
|
|
goto badopt;
|
|
break;
|
|
default:
|
|
badopt:
|
|
/*
|
|
* If there was a problem, coach the user.
|
|
*/
|
|
eprint("Usage: format [-s][-d disk_name]");
|
|
eprint("[-t disk_type][-p partition_name]\n");
|
|
eprint("\t[-f cmd_file][-l log_file]");
|
|
eprint("[-x data_file] disk_list\n");
|
|
fullabort();
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* All the command line strings were options. Return that fact.
|
|
*/
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* This routine reads in and digests the data file. The data file contains
|
|
* definitions for the search path, known disk types, and known partition
|
|
* maps.
|
|
*/
|
|
sup_init()
|
|
{
|
|
char *filename;
|
|
int status;
|
|
TOKEN token, cleaned;
|
|
|
|
/*
|
|
* If the data file was specified on the command line, use it.
|
|
*/
|
|
if (option_x)
|
|
filename = option_x;
|
|
else {
|
|
/*
|
|
* Data file was not specified. Look in the current
|
|
* directory first, and if that fails look in /etc.
|
|
* Assume the name of the file is 'format.dat'.
|
|
*/
|
|
filename = "format.dat";
|
|
data_file = fopen(filename, "r");
|
|
if (data_file != NULL)
|
|
goto opened;
|
|
filename = "/etc/format.dat";
|
|
}
|
|
/*
|
|
* If no data file could be found, we're history.
|
|
*/
|
|
data_file = fopen(filename, "r");
|
|
if (data_file == NULL) {
|
|
eprint("Unable to open data file '%s'.\n", filename);
|
|
fullabort();
|
|
}
|
|
opened:
|
|
/*
|
|
* Step through the data file a meta-line at a time. There are
|
|
* typically several backslashed newlines in each meta-line,
|
|
* so data_lineno will be getting side effected along the way.
|
|
*/
|
|
for (data_lineno = 1;; data_lineno++) {
|
|
/*
|
|
* Get the keyword.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit the end of the data file, we're done.
|
|
*/
|
|
if (status == SUP_EOF)
|
|
break;
|
|
/*
|
|
* If the line is blank, skip it.
|
|
*/
|
|
if (status == SUP_EOL)
|
|
continue;
|
|
/*
|
|
* If the line starts with some key character, it's an error.
|
|
*/
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting keyword, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Clean up the token and see which keyword it is. Call
|
|
* the appropriate routine to process the rest of the line.
|
|
*/
|
|
clean_token(cleaned, token);
|
|
if (strcmp(cleaned, "search_path") == 0)
|
|
sup_setpath();
|
|
else if (strcmp(cleaned, "disk_type") == 0)
|
|
sup_setdtype();
|
|
else if (strcmp(cleaned, "partition") == 0)
|
|
sup_setpart();
|
|
else {
|
|
eprint("Bad keyword '%s' ", cleaned);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
}
|
|
/*
|
|
* Close the data file.
|
|
*/
|
|
(void) fclose(data_file);
|
|
}
|
|
|
|
/*
|
|
* This routine processes a 'search_path' line in the data file. The
|
|
* search path is a list of disk names that will be searched for by the
|
|
* program.
|
|
*/
|
|
sup_setpath()
|
|
{
|
|
TOKEN token, cleaned;
|
|
int status, count;
|
|
|
|
/*
|
|
* Only allow one definition of the search path.
|
|
*/
|
|
if (search_path != NULL) {
|
|
eprint("Search path redefined -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_EQL) {
|
|
eprint("Expecting '=', found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Allocate space for the first entry.
|
|
*/
|
|
search_path = (char **)zalloc(sizeof (char *));
|
|
count = 1;
|
|
/*
|
|
* Loop through the entries.
|
|
*/
|
|
for (;;) {
|
|
/*
|
|
* Pull in the disk name.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit end of line, we're done.
|
|
*/
|
|
if (status == SUP_EOL)
|
|
break;
|
|
/*
|
|
* If we hit some key character, it's an error.
|
|
*/
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting value, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(cleaned, token);
|
|
/*
|
|
* If there are meta characters then lets expand them
|
|
*/
|
|
if (strchr(cleaned,'?') || strchr(cleaned,'[')){
|
|
add_metadevices(cleaned,&count);
|
|
}
|
|
else {
|
|
add_device(cleaned,&count);
|
|
}
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status == SUP_EOL)
|
|
break;
|
|
if (status != SUP_COMMA) {
|
|
eprint("Expecting ',', found '%s' ", token);
|
|
eprint(" -- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
}
|
|
}
|
|
|
|
char *ascii = "0123456789abcdef";
|
|
/*
|
|
* This routine processes the meta characters in a device name
|
|
*
|
|
* The currently supported meta characters are
|
|
* ? a digit from 0-0xF
|
|
* [a-b] range of values from a to b inclusive
|
|
* [abc] use a,b & c individually
|
|
*
|
|
*/
|
|
add_metadevices(cleaned,count)
|
|
TOKEN cleaned;
|
|
int *count;
|
|
{
|
|
|
|
TOKEN hold;
|
|
int i;
|
|
char *pos,*close,*cur;
|
|
char * c;
|
|
char *start,*end;
|
|
|
|
/*
|
|
* check if there is a '?' in the string
|
|
*/
|
|
if (strchr(cleaned,'?') != NULL) {
|
|
for (i = 0 ; i < 0x10 ; i++) {
|
|
(void) strncpy(hold,cleaned,sizeof(TOKEN));
|
|
c = strchr(hold,'?');
|
|
if (i < 0xA)
|
|
*c = i + '0';
|
|
else
|
|
*c = (i - 0xA) + 'a';
|
|
add_metadevices(hold,count);
|
|
}
|
|
} else if ((cur = pos = strchr(cleaned,'[')) != NULL) {
|
|
close = strchr(cleaned,']');
|
|
if (close == NULL){
|
|
eprint("Expecting ']' ");
|
|
goto abort;
|
|
}
|
|
while (++cur < close) {
|
|
if (!isxdigit(*cur)){
|
|
eprint("Expecting digit ");
|
|
goto abort;
|
|
}
|
|
/*
|
|
* check if they want a range of values
|
|
*/
|
|
if (*(cur + 1) == '-') {
|
|
if (!isxdigit(*(cur + 2))){
|
|
eprint("Expecting digit ");
|
|
goto abort;
|
|
}
|
|
start = strchr(ascii,*cur);
|
|
end = strchr(ascii,*(cur + 2));
|
|
if (start == NULL || end == NULL) {
|
|
eprint("Expecting lower case ");
|
|
goto abort;
|
|
}
|
|
/*
|
|
* Build a device name for each digit
|
|
*/
|
|
while (start <= end) {
|
|
bzero(hold,sizeof(TOKEN));
|
|
if (pos != cleaned)
|
|
strncpy(hold,cleaned,pos - cleaned);
|
|
strncat(hold,start,1);
|
|
strcat(hold,close + 1);
|
|
add_metadevices(hold,count);
|
|
start++;
|
|
}
|
|
cur += 2;
|
|
}
|
|
else {
|
|
bzero(hold,sizeof(TOKEN));
|
|
if (pos != cleaned)
|
|
strncpy(hold,cleaned,pos - cleaned);
|
|
strncat(hold,cur,1);
|
|
strcat(hold,close + 1);
|
|
add_metadevices(hold,count);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
add_device(cleaned,count);
|
|
}
|
|
return;
|
|
abort:
|
|
eprint(" -- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
|
|
/*
|
|
* This routine adds a device name to the search path
|
|
*/
|
|
add_device(cleaned,count)
|
|
TOKEN cleaned;
|
|
int *count;
|
|
{
|
|
char filename[DK_DEVLEN + 8] ;
|
|
struct stat buf;
|
|
int i;
|
|
|
|
/*
|
|
* Check if there is a device entry for it
|
|
* The reason that this is done is that if the search path
|
|
* gets over about 4000 entries the behavior of the rezalloc,
|
|
* zalloc calls becomes n*n. This eats up a lot of memory
|
|
* and would panic MUNIX. This is a "feature" of the current
|
|
* malloc algorithm. Doing this also protects against
|
|
* changes in the malloc algorithm in the future since most
|
|
* smaller systems will not have a lot of dev entries
|
|
*/
|
|
filename[0] = '\0';
|
|
(void) strcat(filename, "/dev/r");
|
|
(void) strncat(filename, cleaned, DK_DEVLEN);
|
|
i = strlen(filename);
|
|
filename[i] = 'c';
|
|
filename[i+1] = '\0';
|
|
if (stat(filename,&buf) < 0)
|
|
return;
|
|
|
|
/*
|
|
* Reallocate the search path array to be one larger.
|
|
*/
|
|
search_path = (char **)rezalloc((char *)search_path,
|
|
(sizeof (char *)) * (*count + 1));
|
|
/*
|
|
* Allocate space for the disk name and copy it in.
|
|
*/
|
|
search_path[*count - 1] = zalloc(strlen(cleaned) + 1);
|
|
(void) strcpy(search_path[*count - 1], cleaned);
|
|
/*
|
|
* Terminate the array with a null.
|
|
*/
|
|
search_path[(*count)++] = NULL;
|
|
}
|
|
|
|
/*
|
|
* This routine processes a 'disk_type' line in the data file. It defines
|
|
* the physical attributes of a brand of disk when connected to a specific
|
|
* controller type.
|
|
*/
|
|
sup_setdtype()
|
|
{
|
|
TOKEN token, cleaned, ident;
|
|
int val, status, i;
|
|
u_long flags = 0;
|
|
struct disk_type *dtype, *type;
|
|
struct ctlr_type *ctype;
|
|
char *dtype_name, *ptr;
|
|
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_EQL) {
|
|
eprint("Expecting '=', found '%s' ", token);
|
|
eprint(" -- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the name of the disk type.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting value, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(cleaned, token);
|
|
/*
|
|
* Allocate space for the disk type and copy in the name.
|
|
*/
|
|
dtype_name = zalloc(strlen(cleaned) + 1);
|
|
(void) strcpy(dtype_name, cleaned);
|
|
dtype = (struct disk_type *)zalloc(sizeof (*dtype));
|
|
dtype->dtype_asciilabel = dtype_name;
|
|
/*
|
|
* Loop for each attribute.
|
|
*/
|
|
for (;;) {
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit end of line, we're done.
|
|
*/
|
|
if (status == SUP_EOL)
|
|
break;
|
|
if (status != SUP_COLON) {
|
|
eprint("Expecting ':', found '%s' ", token);
|
|
eprint(" -- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the attribute.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit end of line, we're done.
|
|
*/
|
|
if (status == SUP_EOL)
|
|
break;
|
|
/*
|
|
* If we hit a key character, it's an error.
|
|
*/
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting keyword, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(ident, token);
|
|
/*
|
|
* Check to see if we've got a change specification.
|
|
* If so, this routine will parse the entire
|
|
* specification, so just restart at top of loop.
|
|
*/
|
|
if (sup_change_spec(dtype, ident)) {
|
|
continue;
|
|
}
|
|
/*
|
|
* Pull in more grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_EQL) {
|
|
eprint("Expecting '=', found '%s' ", token);
|
|
eprint(" -- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the value of the attribute.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting value, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(cleaned, token);
|
|
/*
|
|
* If the attribute defined the ctlr...
|
|
*/
|
|
if (strcmp(ident, "ctlr") == 0) {
|
|
/*
|
|
* Match the value with a ctlr type.
|
|
*/
|
|
for (i = 0; i < nctypes; i++)
|
|
if (strcmp(ctlr_types[i].ctype_name,
|
|
cleaned) == 0)
|
|
break;
|
|
/*
|
|
* If we couldn't match it, it's an error.
|
|
*/
|
|
if (i >= nctypes) {
|
|
eprint("Value '%s' is not a known ctlr name ",
|
|
cleaned);
|
|
eprint("-- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Found a match. Add this disk type to the list
|
|
* for the ctlr type.
|
|
*/
|
|
ctype = &ctlr_types[i];
|
|
type = ctype->ctype_dlist;
|
|
if (type == NULL)
|
|
ctype->ctype_dlist = dtype;
|
|
else {
|
|
while (type->dtype_next != NULL)
|
|
type = type->dtype_next;
|
|
type->dtype_next = dtype;
|
|
}
|
|
/*
|
|
* Note that this attribute is defined.
|
|
*/
|
|
flags |= SUP_CTLR;
|
|
continue;
|
|
}
|
|
/*
|
|
* All other attributes require a numeric value. Convert
|
|
* the value to a number.
|
|
*/
|
|
val = (int)strtol(cleaned, &ptr, 0);
|
|
if (*ptr != '\0') {
|
|
eprint("Value '%s' is not an integer ", cleaned);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Figure out which attribute it was and fill in the
|
|
* appropriate value. Also note that the attribute
|
|
* has been defined.
|
|
*/
|
|
if (strcmp(ident, "ncyl") == 0) {
|
|
dtype->dtype_ncyl = val;
|
|
flags |= SUP_NCYL;
|
|
} else if (strcmp(ident, "acyl") == 0) {
|
|
dtype->dtype_acyl = val;
|
|
flags |= SUP_ACYL;
|
|
} else if (strcmp(ident, "pcyl") == 0) {
|
|
dtype->dtype_pcyl = val;
|
|
flags |= SUP_PCYL;
|
|
} else if (strcmp(ident, "nhead") == 0) {
|
|
dtype->dtype_nhead = val;
|
|
flags |= SUP_NHEAD;
|
|
} else if (strcmp(ident, "nsect") == 0) {
|
|
dtype->dtype_nsect = val;
|
|
flags |= SUP_NSECT;
|
|
} else if (strcmp(ident, "rpm") == 0) {
|
|
dtype->dtype_rpm = val;
|
|
flags |= SUP_RPM;
|
|
} else if (strcmp(ident, "bpt") == 0) {
|
|
dtype->dtype_bpt = val;
|
|
flags |= SUP_BPT;
|
|
} else if (strcmp(ident, "bps") == 0) {
|
|
dtype->dtype_bps = val;
|
|
flags |= SUP_BPS;
|
|
} else if (strcmp(ident, "drive_type") == 0) {
|
|
dtype->dtype_dr_type = val;
|
|
flags |= SUP_DRTYPE;
|
|
} else if (strcmp(ident, "skew") == 0) {
|
|
dtype->dtype_buf_sk = val;
|
|
flags |= SUP_SKEW;
|
|
} else if (strcmp(ident, "precomp") == 0) {
|
|
dtype->dtype_wr_prcmp = val;
|
|
flags |= SUP_PRCMP;
|
|
} else if (strcmp(ident, "cache") == 0) {
|
|
dtype->dtype_cache = val;
|
|
flags |= SUP_CACHE;
|
|
} else if (strcmp(ident, "prefetch") == 0) {
|
|
dtype->dtype_threshold = val;
|
|
flags |= SUP_PREFETCH;
|
|
} else if (strcmp(ident, "min_prefetch") == 0) {
|
|
dtype->dtype_prefetch_min = val;
|
|
flags |= SUP_CACHE_MIN;
|
|
} else if (strcmp(ident, "max_prefetch") == 0) {
|
|
dtype->dtype_prefetch_max = val;
|
|
flags |= SUP_CACHE_MAX;
|
|
} else if (strcmp(ident, "trks_zone") == 0) {
|
|
dtype->dtype_trks_zone = val;
|
|
flags |= SUP_TRKS_ZONE;
|
|
} else if (strcmp(ident, "atrks") == 0) {
|
|
dtype->dtype_atrks = val;
|
|
flags |= SUP_ATRKS;
|
|
} else if (strcmp(ident, "asect") == 0) {
|
|
dtype->dtype_asect = val;
|
|
flags |= SUP_ASECT;
|
|
} else if (strcmp(ident, "fmt_time") == 0) {
|
|
dtype->dtype_fmt_time = val;
|
|
} else if (strcmp(ident, "cyl_skew") == 0) {
|
|
dtype->dtype_cyl_skew = val;
|
|
flags |= SUP_CYLSKEW;
|
|
} else if (strcmp(ident, "trk_skew") == 0) {
|
|
dtype->dtype_trk_skew = val;
|
|
flags |= SUP_TRKSKEW;
|
|
} else if (strcmp(ident, "phead") == 0) {
|
|
dtype->dtype_phead = val;
|
|
flags |= SUP_PHEAD;
|
|
} else if (strcmp(ident, "psect") == 0) {
|
|
dtype->dtype_psect = val;
|
|
flags |= SUP_PSECT;
|
|
} else if (strcmp(ident, "read_retries") == 0) {
|
|
dtype->dtype_read_retries = val;
|
|
flags |= SUP_READ_RETRIES;
|
|
} else if (strcmp(ident, "write_retries") == 0) {
|
|
dtype->dtype_write_retries = val;
|
|
flags |= SUP_WRITE_RETRIES;
|
|
} else {
|
|
eprint("Bad keyword '%s' -- line %d of data file.\n",
|
|
ident, data_lineno);
|
|
fullabort();
|
|
}
|
|
}
|
|
/*
|
|
* Check to be sure all the necessary attributes have been defined.
|
|
* If any are missing, it's an error. Also, log options for later
|
|
* use by specific driver.
|
|
*/
|
|
dtype->dtype_options = flags;
|
|
if ((flags & SUP_MIN_DRIVE) != SUP_MIN_DRIVE) {
|
|
eprint("Incomplete specification -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
if ((ctype->ctype_flags & CF_SMD_DEFS) && (!(flags & SUP_BPS))) {
|
|
eprint("Incomplete specification -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
if ((ctype->ctype_flags & CF_450_TYPES) && (!(flags & SUP_DRTYPE))) {
|
|
eprint("Incomplete specification -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
if ((ctype->ctype_flags & CF_BSK_WPR) && (!(flags & SUP_SKEW))) {
|
|
eprint("Incomplete specification -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
if ((ctype->ctype_flags & CF_BSK_WPR) && (!(flags & SUP_PRCMP))) {
|
|
eprint("Incomplete specification -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This routine processes a 'partition' line in the data file. It defines
|
|
* a known partition map for a particular disk type on a particular
|
|
* controller type.
|
|
*/
|
|
sup_setpart()
|
|
{
|
|
TOKEN token, cleaned, disk, ctlr, ident;
|
|
struct disk_type *dtype;
|
|
struct ctlr_type *ctype;
|
|
struct partition_info *pinfo, *parts;
|
|
char *pinfo_name, *ptr;
|
|
int i, index, status, val1, val2, flags = 0;
|
|
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_EQL) {
|
|
eprint("Expecting '=', found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the name of the map.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting value, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(cleaned, token);
|
|
/*
|
|
* Allocate space for the partition map and fill in the name.
|
|
*/
|
|
pinfo_name = zalloc(strlen(cleaned) + 1);
|
|
(void) strcpy(pinfo_name, cleaned);
|
|
pinfo = (struct partition_info *)zalloc(sizeof (*pinfo));
|
|
pinfo->pinfo_name = pinfo_name;
|
|
/*
|
|
* Loop for each attribute in the line.
|
|
*/
|
|
for (;;) {
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit end of line, we're done.
|
|
*/
|
|
if (status == SUP_EOL)
|
|
break;
|
|
if (status != SUP_COLON) {
|
|
eprint("Expecting ':', found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the attribute.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit end of line, we're done.
|
|
*/
|
|
if (status == SUP_EOL)
|
|
break;
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting keyword, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(ident, token);
|
|
/*
|
|
* Pull in more grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_EQL) {
|
|
eprint("Expecting '=', found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the value of the attribute.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
/*
|
|
* If we hit a key character, it's an error.
|
|
*/
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting value, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(cleaned, token);
|
|
/*
|
|
* If the attribute is the ctlr, save the ctlr name and
|
|
* mark it defined.
|
|
*/
|
|
if (strcmp(ident, "ctlr") == 0) {
|
|
(void) strcpy(ctlr, cleaned);
|
|
flags |= SUP_CTLR;
|
|
continue;
|
|
/*
|
|
* If the attribute is the disk, save the disk name and
|
|
* mark it defined.
|
|
*/
|
|
} else if (strcmp(ident, "disk") == 0) {
|
|
(void) strcpy(disk, cleaned);
|
|
flags |= SUP_DISK;
|
|
continue;
|
|
}
|
|
/*
|
|
* All other attributes have a pair of numeric values.
|
|
* Convert the first value to a number.
|
|
*/
|
|
val1 = (int)strtol(cleaned, &ptr, 0);
|
|
if (*ptr != '\0') {
|
|
eprint("Value '%s' is not an integer ", cleaned);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in some grammar.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_COMMA) {
|
|
eprint("Expecting ',', found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Pull in the second value.
|
|
*/
|
|
status = sup_gettoken(token);
|
|
if (status != SUP_STRING) {
|
|
eprint("Expecting value, found '%s' ", token);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
clean_token(cleaned, token);
|
|
/*
|
|
* Convert the second value to a number.
|
|
*/
|
|
val2 = (int)strtol(cleaned, &ptr, 0);
|
|
if (*ptr != '\0') {
|
|
eprint("Value '%s' is not an integer ", cleaned);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* The rest of the attributes are all single letters.
|
|
* Make sure the specified attribute is a single letter.
|
|
*/
|
|
if (strlen(ident) != 1) {
|
|
eprint("Bad keyword '%s' -- line %d of data file.\n",
|
|
ident, data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Also make sure it is within the legal range of letters.
|
|
*/
|
|
if (ident[0] < 'a' || ident[0] > 'h') {
|
|
eprint("Bad keyword '%s' -- line %d of data file.\n",
|
|
ident, data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Fill in the appropriate map entry with the values.
|
|
*/
|
|
index = ident[0] - 'a';
|
|
pinfo->pinfo_map[index].dkl_cylno = val1;
|
|
pinfo->pinfo_map[index].dkl_nblk = val2;
|
|
}
|
|
/*
|
|
* Check to be sure that all necessary attributes were defined.
|
|
*/
|
|
if ((flags & SUP_MIN_PART) != SUP_MIN_PART) {
|
|
eprint("Incomplete specification -- line %d of data file.\n",
|
|
data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Attempt to match the specified ctlr to a known type.
|
|
*/
|
|
for (i = 0; i < nctypes; i++)
|
|
if (strcmp(ctlr_types[i].ctype_name, ctlr) == 0)
|
|
break;
|
|
/*
|
|
* If no match is found, it's an error.
|
|
*/
|
|
if (i >= nctypes) {
|
|
eprint("Value '%s' is not a known ctlr name ", ctlr);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
ctype = &ctlr_types[i];
|
|
/*
|
|
* Attempt to match the specified disk to a known type.
|
|
*/
|
|
for (dtype = ctype->ctype_dlist; dtype != NULL;
|
|
dtype = dtype->dtype_next)
|
|
if (strcmp(dtype->dtype_asciilabel, disk) == 0)
|
|
break;
|
|
/*
|
|
* If no match is found, it's an error.
|
|
*/
|
|
if (dtype == NULL) {
|
|
eprint("Value '%s' is not a known disk name ", disk);
|
|
eprint("-- line %d of data file.\n", data_lineno);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Add this partition map to the list of known maps for the
|
|
* specified disk/ctlr.
|
|
*/
|
|
parts = dtype->dtype_plist;
|
|
if (parts == NULL)
|
|
dtype->dtype_plist = pinfo;
|
|
else {
|
|
while (parts->pinfo_next != NULL)
|
|
parts = parts->pinfo_next;
|
|
parts->pinfo_next = pinfo;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This routine opens the raw C partition of the specified disk with
|
|
* the specified flags.
|
|
*/
|
|
int
|
|
open_disk(diskname, flags)
|
|
char *diskname;
|
|
int flags;
|
|
{
|
|
char filename[DK_DEVLEN + 8];
|
|
int i;
|
|
|
|
/*
|
|
* Construct the pathname for the given disk.
|
|
*/
|
|
filename[0] = '\0';
|
|
(void) strcat(filename, "/dev/r");
|
|
(void) strncat(filename, diskname, DK_DEVLEN);
|
|
i = strlen(filename);
|
|
filename[i] = 'c';
|
|
filename[i+1] = '\0';
|
|
/*
|
|
* Open the disk and return status.
|
|
*/
|
|
return (open(filename, flags));
|
|
}
|
|
|
|
/*
|
|
* This routine performs the disk search during startup. It looks for
|
|
* all the disks in the search path, and creates a list of those that
|
|
* are found.
|
|
*/
|
|
do_search(arglist)
|
|
char *arglist[];
|
|
{
|
|
register struct disk_info *search_disk, *dptr;
|
|
register struct ctlr_info *search_ctlr, *cptr;
|
|
struct disk_type *search_dtype, *type;
|
|
struct partition_info *search_parts, *parts;
|
|
struct dk_conf search_ioctl;
|
|
struct dk_label search_label;
|
|
struct ctlr_ops *ops;
|
|
int search_file, i, status;
|
|
|
|
/*
|
|
* Assume we're talking to a driver which supports
|
|
* the uscsi interface, if SCSI. If the driver is
|
|
* actually the sun4 driver, the first uscsi ioctl
|
|
* will fail, and that and future ioctls will be
|
|
* redirected to the old "generic" interface via
|
|
* this flag.
|
|
*/
|
|
sun4_flag = 0;
|
|
|
|
printf("Searching for disks...");
|
|
(void) fflush(stdout);
|
|
/*
|
|
* If there wasn't a search path defined in the data file or on
|
|
* the command line, there's nothing we can do.
|
|
*/
|
|
if (arglist == NULL)
|
|
goto out;
|
|
/*
|
|
* Step through the array of disks on the search list.
|
|
*/
|
|
for (; *arglist != NULL; arglist++) {
|
|
/*
|
|
* Attempt to open the disk. If it fails, skip it.
|
|
*/
|
|
if ((search_file = open_disk(*arglist,
|
|
O_RDWR | FNDELAY)) < 0)
|
|
continue;
|
|
/*
|
|
* Attempt to read the configuration info on the disk.
|
|
* Again, if it fails, we assume the disk's not there.
|
|
* Note we must close the file for the disk before we
|
|
* continue.
|
|
*/
|
|
if (ioctl(search_file, DKIOCGCONF, &search_ioctl) < 0) {
|
|
(void) close(search_file);
|
|
continue;
|
|
}
|
|
/*
|
|
* Here we play a little trick, if we've got ourselves
|
|
* a SCSI device. We get the inquiry information,
|
|
* and, if what we're looking at is not an MD21
|
|
* device, we convert the ctype from DKC_MD21 to
|
|
* DKC_SCSI_CCS.
|
|
*/
|
|
if (search_ioctl.dkc_ctype == DKC_MD21) {
|
|
static char *emustring = "EMULEX MD21/S2";
|
|
char inqbuf[255];
|
|
struct scsi_inquiry *inq;
|
|
if (uscsi_inquiry(search_file, inqbuf, sizeof (inqbuf))) {
|
|
/*
|
|
* Inquiry failed - punt
|
|
*/
|
|
(void) close(search_file);
|
|
continue;
|
|
}
|
|
inq = (struct scsi_inquiry *) inqbuf;
|
|
if (bcmp(inq->inq_vid, emustring,
|
|
strlen(emustring)) != 0) {
|
|
search_ioctl.dkc_ctype = DKC_SCSI_CCS;
|
|
}
|
|
}
|
|
/*
|
|
* The disk appears to be present. Allocate space for the
|
|
* disk structure and add it to the list of found disks.
|
|
*/
|
|
search_disk = (struct disk_info *)zalloc(sizeof *search_disk);
|
|
if (disk_list == NULL)
|
|
disk_list = search_disk;
|
|
else {
|
|
for (dptr = disk_list; dptr->disk_next != NULL;
|
|
dptr = dptr->disk_next)
|
|
;
|
|
dptr->disk_next = search_disk;
|
|
}
|
|
/*
|
|
* Fill in some info from the ioctl.
|
|
*/
|
|
search_disk->disk_unit = search_ioctl.dkc_unit;
|
|
search_disk->disk_slave = search_ioctl.dkc_slave;
|
|
/*
|
|
* Try to match the ctlr for this disk with a ctlr we
|
|
* have already found. A match is assumed if the ctlrs
|
|
* are at the same address && ctypes agree
|
|
*/
|
|
for (search_ctlr = ctlr_list; search_ctlr != NULL;
|
|
search_ctlr = search_ctlr->ctlr_next)
|
|
if (search_ctlr->ctlr_addr == search_ioctl.dkc_addr &&
|
|
search_ctlr->ctlr_space == search_ioctl.dkc_space
|
|
&& search_ctlr->ctlr_ctype->ctype_ctype ==
|
|
search_ioctl.dkc_ctype)
|
|
break;
|
|
/*
|
|
* If no match was found, we need to identify this ctlr.
|
|
*/
|
|
if (search_ctlr == NULL) {
|
|
/*
|
|
* Match the type of the ctlr to a known type.
|
|
*/
|
|
for (i = 0; i < nctypes; i++)
|
|
if (ctlr_types[i].ctype_ctype ==
|
|
search_ioctl.dkc_ctype)
|
|
break;
|
|
/*
|
|
* If no match was found, it's an error.
|
|
* Close the disk and report the error.
|
|
*/
|
|
if (i >= nctypes) {
|
|
eprint("\nError: found disk attached to ");
|
|
eprint("unsupported controller type '%d'.\n",
|
|
search_ioctl.dkc_ctype);
|
|
(void) close(search_file);
|
|
continue;
|
|
}
|
|
/*
|
|
* Allocate space for the ctlr structure and add it
|
|
* to the list of found ctlrs.
|
|
*/
|
|
search_ctlr = (struct ctlr_info *)
|
|
zalloc(sizeof *search_ctlr);
|
|
search_ctlr->ctlr_ctype = &ctlr_types[i];
|
|
if (ctlr_list == NULL)
|
|
ctlr_list = search_ctlr;
|
|
else {
|
|
for (cptr = ctlr_list; cptr->ctlr_next != NULL;
|
|
cptr = cptr->ctlr_next)
|
|
;
|
|
cptr->ctlr_next = search_ctlr;
|
|
}
|
|
/*
|
|
* Fill in info from the ioctl.
|
|
*/
|
|
for (i = 0; i < DK_DEVLEN; i++) {
|
|
search_ctlr->ctlr_cname[i] =
|
|
search_ioctl.dkc_cname[i];
|
|
search_ctlr->ctlr_dname[i] =
|
|
search_ioctl.dkc_dname[i];
|
|
}
|
|
search_ctlr->ctlr_flags = search_ioctl.dkc_flags;
|
|
search_ctlr->ctlr_num = search_ioctl.dkc_cnum;
|
|
search_ctlr->ctlr_addr = search_ioctl.dkc_addr;
|
|
search_ctlr->ctlr_space = search_ioctl.dkc_space;
|
|
search_ctlr->ctlr_prio = search_ioctl.dkc_prio;
|
|
search_ctlr->ctlr_vec = search_ioctl.dkc_vec;
|
|
}
|
|
/*
|
|
* By this point, we have a known ctlr. Link the disk
|
|
* to the ctlr.
|
|
*/
|
|
search_disk->disk_ctlr = search_ctlr;
|
|
/*
|
|
* Attempt to read the primary label. Try twice.
|
|
*/
|
|
ops = search_ctlr->ctlr_ctype->ctype_ops;
|
|
status = (*ops->rdwr)(DIR_READ, search_file, (daddr_t)0, 1,
|
|
(char *)&search_label, F_SILENT);
|
|
/*
|
|
* SCSI may need second or thind chance before it's ready.
|
|
*/
|
|
if (status != 0) {
|
|
(void) (*ops->rdwr)(DIR_READ, search_file, (daddr_t)0, 1,
|
|
(char *)&search_label, F_SILENT);
|
|
status = (*ops->rdwr)(DIR_READ, search_file, (daddr_t)0, 1,
|
|
(char *)&search_label, F_SILENT);
|
|
}
|
|
/*
|
|
* Close the file for this disk.
|
|
*/
|
|
(void) close(search_file);
|
|
/*
|
|
* If we didn't successfully read the label, or the label
|
|
* appears corrupt, just leave the disk as an unknown type.
|
|
*/
|
|
if (status)
|
|
continue;
|
|
if (!checklabel(&search_label))
|
|
continue;
|
|
if (trim_id(search_label.dkl_asciilabel))
|
|
continue;
|
|
/*
|
|
* The label looks ok. Mark the disk as labeled.
|
|
*/
|
|
search_disk->disk_flags |= DSK_LABEL;
|
|
/*
|
|
* Attempt to match the disk type in the label with a
|
|
* known disk type.
|
|
*/
|
|
for (search_dtype = search_ctlr->ctlr_ctype->ctype_dlist;
|
|
search_dtype != NULL;
|
|
search_dtype = search_dtype->dtype_next)
|
|
if (dtype_match(&search_label, search_dtype))
|
|
break;
|
|
/*
|
|
* If no match was found, we need to create a disk type
|
|
* for this disk.
|
|
*/
|
|
if (search_dtype == NULL) {
|
|
/*
|
|
* Allocate space for the disk type and add it
|
|
* to the list of disk types for this ctlr type.
|
|
*/
|
|
search_dtype = (struct disk_type *)
|
|
zalloc(sizeof *search_dtype);
|
|
type = search_ctlr->ctlr_ctype->ctype_dlist;
|
|
if (type == NULL)
|
|
search_ctlr->ctlr_ctype->ctype_dlist =
|
|
search_dtype;
|
|
else {
|
|
while (type->dtype_next != NULL)
|
|
type = type->dtype_next;
|
|
type->dtype_next = search_dtype;
|
|
}
|
|
/*
|
|
* Fill in the drive info from the disk label.
|
|
*/
|
|
search_dtype->dtype_next = NULL;
|
|
search_dtype->dtype_asciilabel =
|
|
zalloc(strlen(search_label.dkl_asciilabel) + 1);
|
|
(void) strcpy(search_dtype->dtype_asciilabel,
|
|
search_label.dkl_asciilabel);
|
|
search_dtype->dtype_pcyl = search_label.dkl_pcyl;
|
|
search_dtype->dtype_ncyl = search_label.dkl_ncyl;
|
|
search_dtype->dtype_acyl = search_label.dkl_acyl;
|
|
search_dtype->dtype_nhead = search_label.dkl_nhead;
|
|
search_dtype->dtype_nsect = search_label.dkl_nsect;
|
|
search_dtype->dtype_rpm = search_label.dkl_rpm;
|
|
/*
|
|
* Mark the disk as needing specification of
|
|
* ctlr specific attributes. This is necessary
|
|
* because the label doesn't contain these attributes,
|
|
* and they aren't known at this point. They will
|
|
* be asked for if this disk is ever selected by
|
|
* the user.
|
|
*/
|
|
search_dtype->dtype_flags |= DT_NEED_SPEFS;
|
|
}
|
|
/*
|
|
* By this time we have a known disk type. Link the disk
|
|
* to the disk type.
|
|
*/
|
|
search_disk->disk_type = search_dtype;
|
|
/*
|
|
* Attempt to match the partition map in the label with
|
|
* a known partition map for this disk type.
|
|
*/
|
|
for (search_parts = search_dtype->dtype_plist;
|
|
search_parts != NULL;
|
|
search_parts = search_parts->pinfo_next)
|
|
if (parts_match(&search_label, search_parts))
|
|
break;
|
|
/*
|
|
* If no match was made, we need to create a partition
|
|
* map for this disk.
|
|
*/
|
|
if (search_parts == NULL) {
|
|
/*
|
|
* Allocate space for the partition map and add
|
|
* it to the list of maps for this disk type.
|
|
*/
|
|
search_parts = (struct partition_info *)
|
|
zalloc(sizeof *search_parts);
|
|
parts = search_dtype->dtype_plist;
|
|
if (parts == NULL)
|
|
search_dtype->dtype_plist = search_parts;
|
|
else {
|
|
while (parts->pinfo_next != NULL)
|
|
parts = parts->pinfo_next;
|
|
parts->pinfo_next = search_parts;
|
|
}
|
|
search_parts->pinfo_next = NULL;
|
|
/*
|
|
* Fill in the name of the map with a name derived
|
|
* from the name of this disk. This is necessary
|
|
* because the label contains no name for the
|
|
* partition map.
|
|
*/
|
|
i = strlen("original ") + DK_DEVLEN;
|
|
search_parts->pinfo_name = zalloc(i);
|
|
if (search_ctlr->ctlr_ctype->ctype_ctype != DKC_PANTHER) {
|
|
(void) sprintf(search_parts->pinfo_name, "%s%s%d",
|
|
"original ", search_ctlr->ctlr_dname,
|
|
search_disk->disk_unit);
|
|
} else {
|
|
(void) sprintf(search_parts->pinfo_name, "%s%s%03x",
|
|
"original ", search_ctlr->ctlr_dname,
|
|
search_disk->disk_unit);
|
|
}
|
|
/*
|
|
* Fill in the partition info from the disk label.
|
|
*/
|
|
for (i = 0; i < NDKMAP; i++)
|
|
search_parts->pinfo_map[i] =
|
|
search_label.dkl_map[i];
|
|
}
|
|
/*
|
|
* By this time we have a known partitition map. Link the
|
|
* disk to the partition map.
|
|
*/
|
|
search_disk->disk_parts = search_parts;
|
|
}
|
|
/*
|
|
* If we didn't find any disks, give up.
|
|
*/
|
|
out:
|
|
if (disk_list == NULL) {
|
|
if (geteuid() == 0) {
|
|
eprint("No disks found!\n");
|
|
} else {
|
|
eprint("No permission (or no disks found)!\n");
|
|
}
|
|
(void) fflush(stdout);
|
|
fullabort();
|
|
}
|
|
printf("done\n");
|
|
}
|
|
|
|
/*
|
|
* This routine checks to see if a given disk type matches the type
|
|
* in the disk label.
|
|
*/
|
|
int
|
|
dtype_match(label, dtype)
|
|
register struct dk_label *label;
|
|
register struct disk_type *dtype;
|
|
{
|
|
|
|
/*
|
|
* If the any of the physical characteristics are different, or
|
|
* the name is different, it doesn't match.
|
|
*/
|
|
if ((strcmp(label->dkl_asciilabel, dtype->dtype_asciilabel) != 0) ||
|
|
(label->dkl_ncyl != dtype->dtype_ncyl) ||
|
|
(label->dkl_acyl != dtype->dtype_acyl) ||
|
|
(label->dkl_nhead != dtype->dtype_nhead) ||
|
|
(label->dkl_nsect != dtype->dtype_nsect))
|
|
return (0);
|
|
/*
|
|
* If those are all identical, assume it's a match.
|
|
*/
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* This routine checks to see if a given partition map matches the map
|
|
* in the disk label.
|
|
*/
|
|
int
|
|
parts_match(label, pinfo)
|
|
register struct dk_label *label;
|
|
register struct partition_info *pinfo;
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* If any of the partition entries is different, it doesn't match.
|
|
*/
|
|
for (i = 0; i < NDKMAP; i++)
|
|
if ((label->dkl_map[i].dkl_cylno !=
|
|
pinfo->pinfo_map[i].dkl_cylno) ||
|
|
(label->dkl_map[i].dkl_nblk !=
|
|
pinfo->pinfo_map[i].dkl_nblk))
|
|
return (0);
|
|
/*
|
|
* If they are all identical, it's a match.
|
|
*/
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* This routine checks to see if the given disk name refers to the disk
|
|
* in the given disk structure.
|
|
*/
|
|
int
|
|
diskname_match(name, disk)
|
|
char *name;
|
|
register struct disk_info *disk;
|
|
{
|
|
char *ptr;
|
|
int i, len;
|
|
|
|
/*
|
|
* Check to be sure the disk name starts out with the correct
|
|
* letters for this disk type.
|
|
*/
|
|
len = strlen(disk->disk_ctlr->ctlr_dname);
|
|
if (strcnt(name, disk->disk_ctlr->ctlr_dname) != len)
|
|
return (0);
|
|
/*
|
|
* Extract the unit number from the disk name.
|
|
*/
|
|
if (disk->disk_ctlr->ctlr_ctype->ctype_ctype != DKC_PANTHER) {
|
|
i = (int)strtol(name + len, &ptr, 10);
|
|
} else {
|
|
i = (int)strtol(name + len, &ptr, 16);
|
|
}
|
|
if ((ptr - name) != strlen(name))
|
|
return (0);
|
|
/*
|
|
* Make sure the unit number matches.
|
|
*/
|
|
if (i != disk->disk_unit)
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Parse a SCSI mode page change specification.
|
|
*
|
|
* Return:
|
|
* 0: not change specification, continue parsing
|
|
* 1: was change specification, it was ok,
|
|
* or we already handled the error.
|
|
*/
|
|
int
|
|
sup_change_spec(disk, id)
|
|
struct disk_type *disk;
|
|
char *id;
|
|
{
|
|
char *p;
|
|
char *p2;
|
|
int pageno;
|
|
int byteno;
|
|
int mode;
|
|
int value;
|
|
TOKEN token;
|
|
TOKEN ident;
|
|
struct chg_list *cp;
|
|
int tilde;
|
|
int i;
|
|
|
|
/*
|
|
* Syntax: p[<nn>|0x<xx>]
|
|
*/
|
|
if (*id != 'p') {
|
|
return (0);
|
|
}
|
|
pageno = (int) strtol(id+1, &p2, 0);
|
|
if (*p2 != 0) {
|
|
return (0);
|
|
}
|
|
/*
|
|
* Once we get this far, we know we have the
|
|
* beginnings of a change specification.
|
|
* If there's a problem now, we report the problem,
|
|
* and abort.
|
|
*/
|
|
if (!scsi_supported_page(pageno)) {
|
|
eprint("Unsupported mode page '%s'", id);
|
|
fullabort();
|
|
}
|
|
/*
|
|
* Next token should be the byte offset
|
|
*/
|
|
if (sup_gettoken(token) != SUP_STRING) {
|
|
eprint("Unexpected value '%s'", token);
|
|
fullabort();
|
|
}
|
|
clean_token(ident, token);
|
|
|
|
/*
|
|
* Syntax: b[<nn>|0x<xx>]
|
|
*/
|
|
p = ident;
|
|
if (*p++ != 'b') {
|
|
eprint("Unknown keyword '%s'", ident);
|
|
fullabort();
|
|
}
|
|
byteno = (int) strtol(p, &p2, 10);
|
|
if (*p2 != 0) {
|
|
eprint("Unknown keyword '%s'", ident);
|
|
fullabort();
|
|
}
|
|
if (byteno == 0 || byteno == 1) {
|
|
eprint("Unsupported byte offset '%s'", ident);
|
|
fullabort();
|
|
}
|
|
|
|
/*
|
|
* Get the operator for this expression
|
|
*/
|
|
mode = CHG_MODE_UNDEFINED;
|
|
switch (sup_gettoken(token)) {
|
|
case SUP_EQL:
|
|
mode = CHG_MODE_ABS;
|
|
break;
|
|
case SUP_OR:
|
|
if (sup_gettoken(token) == SUP_EQL)
|
|
mode = CHG_MODE_SET;
|
|
break;
|
|
case SUP_AND:
|
|
if (sup_gettoken(token) == SUP_EQL)
|
|
mode = CHG_MODE_CLR;
|
|
break;
|
|
}
|
|
if (mode == CHG_MODE_UNDEFINED) {
|
|
eprint("Unexpected operator: '%s'", token);
|
|
fullabort();
|
|
}
|
|
|
|
/*
|
|
* Get right-hand of expression - accept optional tilde
|
|
*/
|
|
tilde = 0;
|
|
if ((i = sup_gettoken(token)) == SUP_TILDE) {
|
|
tilde = 1;
|
|
i = sup_gettoken(token);
|
|
}
|
|
if (i != SUP_STRING) {
|
|
eprint("Expecting value, found '%s'", token);
|
|
fullabort();
|
|
}
|
|
clean_token(ident, token);
|
|
value = (int) strtol(ident, &p, 0);
|
|
if (*p != 0) {
|
|
eprint("Expecting value, found '%s'", token);
|
|
fullabort();
|
|
}
|
|
|
|
/*
|
|
* Apply the tilde operator, if found.
|
|
* Constrain to a byte value.
|
|
*/
|
|
if (tilde) {
|
|
value = ~value;
|
|
}
|
|
value &= 0xff;
|
|
|
|
/*
|
|
* We parsed a successful change specification expression.
|
|
* Add it to the list for this disk type.
|
|
*/
|
|
cp = new_chg_list(disk);
|
|
cp->pageno = pageno;
|
|
cp->byteno = byteno;
|
|
cp->mode = mode;
|
|
cp->value = value;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* Create a new chg_list structure, and append it onto the
|
|
* end of the current chg_list under construction. By
|
|
* applying changes in the order in which listed in the
|
|
* data file, the changes we make are deterministic.
|
|
* Return a pointer to the new structure, so that the
|
|
* caller can fill in the appropriate information.
|
|
*/
|
|
struct chg_list *
|
|
new_chg_list(disk)
|
|
struct disk_type *disk;
|
|
{
|
|
struct chg_list *cp;
|
|
struct chg_list *nc;
|
|
|
|
nc = (struct chg_list *) malloc(sizeof (struct chg_list));
|
|
|
|
if (disk->dtype_chglist == NULL) {
|
|
disk->dtype_chglist = nc;
|
|
} else {
|
|
for (cp = disk->dtype_chglist; cp->next; cp = cp->next)
|
|
;
|
|
cp->next = nc;
|
|
}
|
|
nc->next = NULL;
|
|
return (nc);
|
|
}
|