Home | History | Annotate | Line # | Download | only in amrctl
amrctl.c revision 1.1.32.1
      1       1.1  bouyer /*-
      2       1.1  bouyer  * Copyright (c) 2002, Pierre David <Pierre.David (at) crc.u-strasbg.fr>
      3       1.1  bouyer  * Copyright (c) 2006, Jung-uk Kim <jkim (at) FreeBSD.org>
      4       1.1  bouyer  * All rights reserved.
      5       1.1  bouyer  *
      6       1.1  bouyer  * Redistribution and use in source and binary forms, with or without
      7       1.1  bouyer  * modification, are permitted provided that the following conditions
      8       1.1  bouyer  * are met:
      9       1.1  bouyer  * 1. Redistributions of source code must retain the above copyright
     10       1.1  bouyer  *    notice unmodified, this list of conditions, and the following
     11       1.1  bouyer  *    disclaimer.
     12       1.1  bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1  bouyer  *    notice, this list of conditions and the following disclaimer in the
     14       1.1  bouyer  *    documentation and/or other materials provided with the distribution.
     15       1.1  bouyer  *
     16       1.1  bouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17       1.1  bouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18       1.1  bouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19       1.1  bouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20       1.1  bouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21       1.1  bouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22       1.1  bouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23       1.1  bouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24       1.1  bouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25       1.1  bouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26       1.1  bouyer  */
     27       1.1  bouyer 
     28       1.1  bouyer #include <sys/cdefs.h>
     29       1.1  bouyer 
     30       1.1  bouyer #include <stdio.h>
     31       1.1  bouyer #include <stdlib.h>
     32       1.1  bouyer #include <string.h>
     33       1.1  bouyer #include <fcntl.h>
     34       1.1  bouyer #include <errno.h>
     35       1.1  bouyer #include <unistd.h>
     36       1.1  bouyer 
     37       1.1  bouyer #include <sys/ioctl.h>
     38       1.1  bouyer 
     39       1.1  bouyer #include <machine/param.h>
     40       1.1  bouyer 
     41       1.1  bouyer #include <dev/pci/amrio.h>
     42       1.1  bouyer #include <dev/pci/amrreg.h>
     43       1.1  bouyer 
     44       1.1  bouyer #define NATTEMPTS	5
     45       1.1  bouyer #define SLEEPTIME	100000	/* microseconds */
     46       1.1  bouyer 
     47       1.1  bouyer int	nattempts = NATTEMPTS;	/* # of attempts before giving up */
     48       1.1  bouyer int	sleeptime = SLEEPTIME;	/* between attempts, in ms */
     49       1.1  bouyer 
     50       1.1  bouyer #define AMR_BUFSIZE	1024
     51       1.1  bouyer 
     52       1.1  bouyer int	enq_result = AMR_STATUS_FAILED;
     53       1.1  bouyer char	enq_buffer[AMR_BUFSIZE];
     54       1.1  bouyer 
     55       1.1  bouyer #define AMR_MAX_NCTRLS	16
     56       1.1  bouyer #define AMR_MAX_NSDEVS	16
     57       1.1  bouyer 
     58       1.1  bouyer u_int8_t	nschan = 0;
     59       1.1  bouyer 
     60       1.1  bouyer /*
     61       1.1  bouyer  * Include lookup tables, and a function to match a code to a string.
     62       1.1  bouyer  *
     63       1.1  bouyer  * XXX Lookup tables cannot be included, since they require symbols from
     64       1.1  bouyer  * amrreg.h which need in turn the _KERNEL define.
     65       1.1  bouyer  */
     66       1.1  bouyer 
     67       1.1  bouyer /* #define AMR_DEFINE_TABLES */
     68       1.1  bouyer /* #include "amr_tables.h" */
     69       1.1  bouyer 
     70       1.1  bouyer int amr_ioctl_enquiry(int, u_int8_t, u_int8_t, u_int8_t);
     71       1.1  bouyer void usage(char *);
     72       1.1  bouyer int describe_card(int, int, int);
     73       1.1  bouyer char * describe_property(u_int8_t, char *);
     74       1.1  bouyer const char * describe_state(int, u_int8_t);
     75       1.1  bouyer void describe_battery(int, int, int, int, int);
     76       1.1  bouyer void describe_one_volume(int, int, u_int32_t, u_int8_t, u_int8_t);
     77       1.1  bouyer void describe_one_drive(int, int, u_int8_t);
     78       1.1  bouyer void describe_drive(int, int, int, int, int);
     79       1.1  bouyer 
     80       1.1  bouyer /*
     81       1.1  bouyer  * Offsets in an amr_user_ioctl.au_cmd [] array See amrio.h
     82       1.1  bouyer  */
     83       1.1  bouyer 
     84       1.1  bouyer #define MB_COMMAND	0
     85       1.1  bouyer #define MB_CHANNEL	1
     86       1.1  bouyer #define MB_PARAM	2
     87       1.1  bouyer #define MB_PAD		3
     88       1.1  bouyer #define MB_DRIVE	4
     89       1.1  bouyer 
     90       1.1  bouyer #define FIRMWARE_40LD	1
     91       1.1  bouyer #define FIRMWARE_8LD	2
     92       1.1  bouyer 
     93       1.1  bouyer static struct {
     94       1.1  bouyer 	const char	*product;
     95  1.1.32.1     jym 	const uint32_t	signature;
     96       1.1  bouyer } prodtable[] = {
     97       1.1  bouyer 	{	"Series 431",			AMR_SIG_431	},
     98       1.1  bouyer 	{	"Series 438",			AMR_SIG_438	},
     99       1.1  bouyer 	{	"Series 762",			AMR_SIG_762	},
    100       1.1  bouyer 	{	"Integrated HP NetRAID (T5)",	AMR_SIG_T5	},
    101       1.1  bouyer 	{	"Series 466",			AMR_SIG_466	},
    102       1.1  bouyer 	{	"Series 467",			AMR_SIG_467	},
    103       1.1  bouyer 	{	"Integrated HP NetRAID (T7)",	AMR_SIG_T7	},
    104       1.1  bouyer 	{	"Series 490",			AMR_SIG_490	}
    105       1.1  bouyer };
    106       1.1  bouyer 
    107       1.1  bouyer static struct {
    108       1.1  bouyer 	const int	code;
    109       1.1  bouyer 	const char	*ifyes, *ifno;
    110       1.1  bouyer } proptable[] = {
    111       1.1  bouyer 	{	AMR_DRV_WRITEBACK,
    112       1.1  bouyer 		"writeback",		"write-through"		},
    113       1.1  bouyer 	{	AMR_DRV_READHEAD,
    114       1.1  bouyer 		"read-ahead",		"no-read-ahead"		},
    115       1.1  bouyer 	{	AMR_DRV_ADAPTIVE,
    116       1.1  bouyer 		"adaptative-io",	"no-adaptative-io"	}
    117       1.1  bouyer };
    118       1.1  bouyer 
    119       1.1  bouyer static struct {
    120       1.1  bouyer 	const int	code;
    121       1.1  bouyer 	const char	*status;
    122       1.1  bouyer } statetable[] = {
    123       1.1  bouyer 	{	AMR_DRV_OFFLINE,	"offline"	},
    124       1.1  bouyer 	{	AMR_DRV_DEGRADED,	"degraded"	},
    125       1.1  bouyer 	{	AMR_DRV_OPTIMAL,	"optimal"	},
    126       1.1  bouyer 	{	AMR_DRV_ONLINE,		"online"	},
    127       1.1  bouyer 	{	AMR_DRV_FAILED,		"failed"	},
    128       1.1  bouyer 	{	AMR_DRV_REBUILD,	"rebuild"	},
    129       1.1  bouyer 	{	AMR_DRV_HOTSPARE,	"hotspare"	}
    130       1.1  bouyer };
    131       1.1  bouyer 
    132       1.1  bouyer static struct {
    133       1.1  bouyer 	const u_int8_t	code;
    134       1.1  bouyer 	const char		*status;
    135       1.1  bouyer } battable[] = {
    136       1.1  bouyer 	{	AMR_BATT_MODULE_MISSING,	"not present"		},
    137       1.1  bouyer 	{	AMR_BATT_LOW_VOLTAGE,		"low voltage"		},
    138       1.1  bouyer 	{	AMR_BATT_TEMP_HIGH,		"high temperature"	},
    139       1.1  bouyer 	{	AMR_BATT_PACK_MISSING,		"pack missing"	},
    140       1.1  bouyer 	{	AMR_BATT_CYCLES_EXCEEDED,	"cycle exceeded"	}
    141       1.1  bouyer };
    142       1.1  bouyer 
    143       1.1  bouyer static struct {
    144       1.1  bouyer 	const u_int8_t	code;
    145       1.1  bouyer 	const char		*status;
    146       1.1  bouyer } bcstatble[] = {
    147       1.1  bouyer 	{	AMR_BATT_CHARGE_DONE,		"charge done"		},
    148       1.1  bouyer 	{	AMR_BATT_CHARGE_INPROG,		"charge in progress"	},
    149       1.1  bouyer 	{	AMR_BATT_CHARGE_FAIL,		"charge failed"		}
    150       1.1  bouyer };
    151       1.1  bouyer 
    152       1.1  bouyer #define NTAB(tab)	(sizeof tab / sizeof tab [0])
    153       1.1  bouyer 
    154       1.1  bouyer int
    155       1.1  bouyer amr_ioctl_enquiry(int fd, u_int8_t cmd, u_int8_t cmdsub, u_int8_t cmdqual)
    156       1.1  bouyer {
    157       1.1  bouyer 	struct amr_user_ioctl am;
    158       1.1  bouyer 	int	r, i;
    159       1.1  bouyer 
    160       1.1  bouyer 	am.au_cmd[MB_COMMAND] = cmd;
    161       1.1  bouyer 	am.au_cmd[MB_CHANNEL] = cmdsub;
    162       1.1  bouyer 	am.au_cmd[MB_PARAM] = cmdqual;
    163       1.1  bouyer 	am.au_cmd[MB_PAD] = 0;
    164       1.1  bouyer 	am.au_cmd[MB_DRIVE] = 0;
    165       1.1  bouyer 
    166       1.1  bouyer 	am.au_buffer = enq_buffer;
    167       1.1  bouyer 	am.au_length = AMR_BUFSIZE;
    168       1.1  bouyer 	am.au_direction = AMR_IO_READ;
    169       1.1  bouyer 	am.au_status = 0;
    170       1.1  bouyer 
    171       1.1  bouyer 	i = 0;
    172       1.1  bouyer 	r = -1;
    173       1.1  bouyer 	while (i < nattempts && r == -1) {
    174       1.1  bouyer 		r = ioctl(fd, AMR_IO_COMMAND, &am);
    175       1.1  bouyer 		if (r == -1) {
    176       1.1  bouyer 			if (errno != EBUSY) {
    177       1.1  bouyer 				perror("ioctl enquiry");
    178       1.1  bouyer 				exit(1);
    179       1.1  bouyer 			} else
    180       1.1  bouyer 				usleep(sleeptime);
    181       1.1  bouyer 		}
    182       1.1  bouyer 		i++;
    183       1.1  bouyer 	}
    184       1.1  bouyer 	return am.au_status;
    185       1.1  bouyer }
    186       1.1  bouyer 
    187       1.1  bouyer void
    188       1.1  bouyer usage(char *prog)
    189       1.1  bouyer {
    190       1.1  bouyer 	fprintf(stderr, "usage: %s stat [-a num] [-b] "
    191       1.1  bouyer 		"[-c ctlr|-f dev] [-g] [-l vol]\n\t\t"
    192       1.1  bouyer 		"[-p drive|-s bus[:target]] [-t usec] [-v]\n\n\t"
    193       1.1  bouyer 		"-a num\t\tnumber of retries\n\t"
    194       1.1  bouyer 		"-b\t\tbattery status\n\t"
    195       1.1  bouyer 		"-c ctrl\t\tcontroller ID\n\t"
    196       1.1  bouyer 		"-f dev\t\tdevice path\n\t"
    197       1.1  bouyer 		"-g\t\tprint global parameters\n\t"
    198       1.1  bouyer 		"-l vol\t\tlogical volume ID\n\t"
    199       1.1  bouyer 		"-p drive\tphysical drive ID\n\t"
    200       1.1  bouyer 		"-s bus[:target]\tSCSI bus (and optinal target)\n\t"
    201       1.1  bouyer 		"-t usec\t\tsleep time between retries\n\t"
    202       1.1  bouyer 		"-v\t\tverbose output\n",
    203       1.1  bouyer 		prog);
    204       1.1  bouyer 	exit(1);
    205       1.1  bouyer }
    206       1.1  bouyer 
    207       1.1  bouyer /******************************************************************************
    208       1.1  bouyer  * Card description
    209       1.1  bouyer  */
    210       1.1  bouyer 
    211       1.1  bouyer int
    212       1.1  bouyer describe_card(int fd, int verbosity, int globalparam)
    213       1.1  bouyer {
    214       1.1  bouyer 	struct amr_enquiry *ae;
    215  1.1.32.1     jym 	uint32_t	cardtype;
    216       1.1  bouyer 
    217       1.1  bouyer 	/*
    218       1.1  bouyer 	 * Try the 40LD firmware interface
    219       1.1  bouyer 	 */
    220       1.1  bouyer 
    221       1.1  bouyer 	enq_result = amr_ioctl_enquiry(fd, AMR_CMD_CONFIG,
    222       1.1  bouyer 		AMR_CONFIG_PRODUCT_INFO, 0);
    223       1.1  bouyer 	if (enq_result == AMR_STATUS_SUCCESS) {
    224       1.1  bouyer 		struct amr_prodinfo *ap;
    225       1.1  bouyer 
    226       1.1  bouyer 		ap = (struct amr_prodinfo *)enq_buffer;
    227       1.1  bouyer 		nschan = ap->ap_nschan;
    228       1.1  bouyer 		if (globalparam) {
    229       1.1  bouyer 			printf("Product\t\t\t<%.80s>\n", ap->ap_product);
    230       1.1  bouyer 			printf("Firmware\t\t%.16s\n", ap->ap_firmware);
    231       1.1  bouyer 			printf("BIOS\t\t\t%.16s\n", ap->ap_bios);
    232       1.1  bouyer 			printf("SCSI channels\t\t%d\n", ap->ap_nschan);
    233       1.1  bouyer 			printf("Fibre loops\t\t%d\n", ap->ap_fcloops);
    234       1.1  bouyer 			printf("Memory size\t\t%d MB\n", ap->ap_memsize);
    235       1.1  bouyer 			if (verbosity >= 1) {
    236       1.1  bouyer 				printf("Ioctl\t\t\t%d (%s)\n", FIRMWARE_40LD,
    237       1.1  bouyer 				       "40LD");
    238       1.1  bouyer 				printf("Signature\t\t0x%08x\n",
    239       1.1  bouyer 				       ap->ap_signature);
    240       1.1  bouyer 				printf("Configsig\t\t0x%08x\n",
    241       1.1  bouyer 				       ap->ap_configsig);
    242       1.1  bouyer 				printf("Subsystem\t\t0x%04x\n",
    243       1.1  bouyer 				       ap->ap_subsystem);
    244       1.1  bouyer 				printf("Subvendor\t\t0x%04x\n",
    245       1.1  bouyer 				       ap->ap_subvendor);
    246       1.1  bouyer 				printf("Notify counters\t\t%d\n",
    247       1.1  bouyer 				       ap->ap_numnotifyctr);
    248       1.1  bouyer 			}
    249       1.1  bouyer 		}
    250       1.1  bouyer 		return FIRMWARE_40LD;
    251       1.1  bouyer 	}
    252       1.1  bouyer 	/*
    253       1.1  bouyer 	 * Try the 8LD firmware interface
    254       1.1  bouyer 	 */
    255       1.1  bouyer 
    256       1.1  bouyer 	enq_result = amr_ioctl_enquiry(fd, AMR_CMD_EXT_ENQUIRY2, 0, 0);
    257       1.1  bouyer 	ae = (struct amr_enquiry *)enq_buffer;
    258       1.1  bouyer 	if (enq_result == AMR_STATUS_SUCCESS) {
    259       1.1  bouyer 		cardtype = ae->ae_signature;
    260       1.1  bouyer 	} else {
    261       1.1  bouyer 		enq_result = amr_ioctl_enquiry(fd, AMR_CMD_ENQUIRY, 0, 0);
    262       1.1  bouyer 		cardtype = 0;
    263       1.1  bouyer 	}
    264       1.1  bouyer 
    265       1.1  bouyer 	if (enq_result == AMR_STATUS_SUCCESS) {
    266       1.1  bouyer 
    267       1.1  bouyer 		if (globalparam) {
    268       1.1  bouyer 			const char   *product = NULL;
    269       1.1  bouyer 			char	bios[100], firmware[100];
    270  1.1.32.1     jym 			size_t	i;
    271       1.1  bouyer 
    272       1.1  bouyer 			for (i = 0; i < NTAB(prodtable); i++) {
    273       1.1  bouyer 				if (cardtype == prodtable[i].signature) {
    274       1.1  bouyer 					product = prodtable[i].product;
    275       1.1  bouyer 					break;
    276       1.1  bouyer 				}
    277       1.1  bouyer 			}
    278       1.1  bouyer 			if (product == NULL)
    279       1.1  bouyer 				product = "unknown card signature";
    280       1.1  bouyer 
    281       1.1  bouyer 			/*
    282       1.1  bouyer 			 * HP NetRaid controllers have a special encoding of
    283       1.1  bouyer 			 * the firmware and BIOS versions. The AMI version
    284       1.1  bouyer 			 * seems to have it as strings whereas the HP version
    285       1.1  bouyer 			 * does it with a leading uppercase character and two
    286       1.1  bouyer 			 * binary numbers.
    287       1.1  bouyer 			 */
    288       1.1  bouyer 
    289       1.1  bouyer 			if (ae->ae_adapter.aa_firmware[2] >= 'A' &&
    290       1.1  bouyer 			    ae->ae_adapter.aa_firmware[2] <= 'Z' &&
    291       1.1  bouyer 			    ae->ae_adapter.aa_firmware[1] < ' ' &&
    292       1.1  bouyer 			    ae->ae_adapter.aa_firmware[0] < ' ' &&
    293       1.1  bouyer 			    ae->ae_adapter.aa_bios[2] >= 'A' &&
    294       1.1  bouyer 			    ae->ae_adapter.aa_bios[2] <= 'Z' &&
    295       1.1  bouyer 			    ae->ae_adapter.aa_bios[1] < ' ' &&
    296       1.1  bouyer 			    ae->ae_adapter.aa_bios[0] < ' ') {
    297       1.1  bouyer 
    298       1.1  bouyer 				/*
    299       1.1  bouyer 				 * looks like we have an HP NetRaid version
    300       1.1  bouyer 				 * of the MegaRaid
    301       1.1  bouyer 				 */
    302       1.1  bouyer 
    303       1.1  bouyer 				if (cardtype == AMR_SIG_438) {
    304       1.1  bouyer 					/*
    305       1.1  bouyer 					 * the AMI 438 is a NetRaid 3si in
    306       1.1  bouyer 					 * HP-land
    307       1.1  bouyer 					 */
    308       1.1  bouyer 					product = "HP NetRaid 3si";
    309       1.1  bouyer 				}
    310       1.1  bouyer 				sprintf(firmware, "%c.%02d.%02d",
    311       1.1  bouyer 					ae->ae_adapter.aa_firmware[2],
    312       1.1  bouyer 					ae->ae_adapter.aa_firmware[1],
    313       1.1  bouyer 					ae->ae_adapter.aa_firmware[0]);
    314       1.1  bouyer 				sprintf(bios, "%c.%02d.%02d",
    315       1.1  bouyer 					ae->ae_adapter.aa_bios[2],
    316       1.1  bouyer 					ae->ae_adapter.aa_bios[1],
    317       1.1  bouyer 					ae->ae_adapter.aa_bios[0]);
    318       1.1  bouyer 			} else {
    319       1.1  bouyer 				sprintf(firmware, "%.4s",
    320       1.1  bouyer 					ae->ae_adapter.aa_firmware);
    321       1.1  bouyer 				sprintf(bios, "%.4s", ae->ae_adapter.aa_bios);
    322       1.1  bouyer 			}
    323       1.1  bouyer 
    324       1.1  bouyer 			printf("Ioctl = %d (%s)\n", FIRMWARE_8LD, "8LD");
    325       1.1  bouyer 			printf("Product =\t<%s>\n", product);
    326       1.1  bouyer 			printf("Firmware =\t%s\n", firmware);
    327       1.1  bouyer 			printf("BIOS =\t%s\n", bios);
    328       1.1  bouyer 			/* printf ("SCSI Channels =\t%d\n", ae->ae_nschan); */
    329       1.1  bouyer 			/* printf ("Fibre Loops =\t%d\n", ae->ae_fcloops); */
    330       1.1  bouyer 			printf("Memory size =\t%d MB\n",
    331       1.1  bouyer 			       ae->ae_adapter.aa_memorysize);
    332       1.1  bouyer 			/*
    333       1.1  bouyer 			 * printf ("Notify counters =\t%d\n",
    334       1.1  bouyer 			 * ae->ae_numnotifyctr) ;
    335       1.1  bouyer 			 */
    336       1.1  bouyer 		}
    337       1.1  bouyer 		return FIRMWARE_8LD;
    338       1.1  bouyer 	}
    339       1.1  bouyer 	/*
    340       1.1  bouyer 	 * Neither firmware interface succeeded. Abort.
    341       1.1  bouyer 	 */
    342       1.1  bouyer 
    343       1.1  bouyer 	fprintf(stderr, "Firmware interface not supported\n");
    344       1.1  bouyer 	exit(1);
    345       1.1  bouyer 
    346       1.1  bouyer }
    347       1.1  bouyer 
    348       1.1  bouyer char *
    349       1.1  bouyer describe_property(u_int8_t prop, char *buffer)
    350       1.1  bouyer {
    351  1.1.32.1     jym 	size_t	i;
    352       1.1  bouyer 
    353       1.1  bouyer 	strcpy(buffer, "<");
    354       1.1  bouyer 	for (i = 0; i < NTAB(proptable); i++) {
    355       1.1  bouyer 		if (i > 0)
    356       1.1  bouyer 			strcat(buffer, ",");
    357       1.1  bouyer 		if (prop & proptable[i].code)
    358       1.1  bouyer 			strcat(buffer, proptable[i].ifyes);
    359       1.1  bouyer 		else
    360       1.1  bouyer 			strcat(buffer, proptable[i].ifno);
    361       1.1  bouyer 	}
    362       1.1  bouyer 	strcat(buffer, ">");
    363       1.1  bouyer 
    364       1.1  bouyer 	return buffer;
    365       1.1  bouyer }
    366       1.1  bouyer 
    367       1.1  bouyer const char *
    368       1.1  bouyer describe_state(int verbosity, u_int8_t state)
    369       1.1  bouyer {
    370  1.1.32.1     jym 	size_t	i;
    371       1.1  bouyer 
    372       1.1  bouyer 	if ((AMR_DRV_PREVSTATE(state) == AMR_DRV_CURSTATE(state)) &&
    373       1.1  bouyer 	    (AMR_DRV_CURSTATE(state) == AMR_DRV_OFFLINE) && verbosity == 0)
    374       1.1  bouyer 		return NULL;
    375       1.1  bouyer 
    376       1.1  bouyer 	for (i = 0; i < NTAB(statetable); i++)
    377       1.1  bouyer 		if (AMR_DRV_CURSTATE(state) == statetable[i].code)
    378       1.1  bouyer 			return (statetable[i].status);
    379       1.1  bouyer 
    380       1.1  bouyer 	return NULL;
    381       1.1  bouyer }
    382       1.1  bouyer 
    383       1.1  bouyer /******************************************************************************
    384       1.1  bouyer  * Battery status
    385       1.1  bouyer  */
    386       1.1  bouyer void
    387       1.1  bouyer describe_battery(int fd, int verbosity, int fwint, int bflags, int globalparam)
    388       1.1  bouyer {
    389       1.1  bouyer 	u_int8_t batt_status;
    390  1.1.32.1     jym 	size_t i;
    391       1.1  bouyer 
    392       1.1  bouyer 	if (fwint == FIRMWARE_40LD) {
    393       1.1  bouyer 		enq_result = amr_ioctl_enquiry(fd, AMR_CMD_CONFIG,
    394       1.1  bouyer 			AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL);
    395       1.1  bouyer 		if (enq_result == AMR_STATUS_SUCCESS) {
    396       1.1  bouyer 			struct amr_enquiry3 *ae3;
    397       1.1  bouyer 
    398       1.1  bouyer 			ae3 = (struct amr_enquiry3 *)enq_buffer;
    399       1.1  bouyer 			if (bflags || globalparam) {
    400       1.1  bouyer 				batt_status = ae3->ae_batterystatus;
    401       1.1  bouyer 				printf("Battery status\t\t");
    402       1.1  bouyer 				for (i = 0; i < NTAB(battable); i++) {
    403       1.1  bouyer 					if (batt_status & battable[i].code)
    404       1.1  bouyer 						printf("%s, ", battable[i].status);
    405       1.1  bouyer 				}
    406       1.1  bouyer 				if (!(batt_status &
    407       1.1  bouyer 				    (AMR_BATT_MODULE_MISSING|AMR_BATT_PACK_MISSING))) {
    408       1.1  bouyer 					for (i = 0; i < NTAB(bcstatble); i++)
    409       1.1  bouyer 						if (bcstatble[i].code ==
    410       1.1  bouyer 						    (batt_status & AMR_BATT_CHARGE_MASK))
    411       1.1  bouyer 							printf("%s", bcstatble[i].status);
    412       1.1  bouyer 				} else
    413       1.1  bouyer 					printf("charge unknown");
    414       1.1  bouyer 				if (verbosity)
    415       1.1  bouyer 					printf(" (0x%02x)", batt_status);
    416       1.1  bouyer 				printf("\n");
    417       1.1  bouyer 			}
    418       1.1  bouyer 		}
    419       1.1  bouyer 	} else if (fwint == FIRMWARE_8LD) {
    420       1.1  bouyer 		/* Nothing to do here. */
    421       1.1  bouyer 		return;
    422       1.1  bouyer 	} else {
    423       1.1  bouyer 		fprintf(stderr, "Firmware interface not supported.\n");
    424       1.1  bouyer 		exit(1);
    425       1.1  bouyer 	}
    426       1.1  bouyer 
    427       1.1  bouyer 	return;
    428       1.1  bouyer }
    429       1.1  bouyer 
    430       1.1  bouyer /******************************************************************************
    431       1.1  bouyer  * Logical volumes
    432       1.1  bouyer  */
    433       1.1  bouyer 
    434       1.1  bouyer void
    435       1.1  bouyer describe_one_volume(int ldrv, int verbosity,
    436       1.1  bouyer 		    u_int32_t size, u_int8_t state, u_int8_t prop)
    437       1.1  bouyer {
    438       1.1  bouyer 	float	szgb;
    439       1.1  bouyer 	int	raid_level;
    440       1.1  bouyer 	char	propstr[MAXPATHLEN];
    441       1.1  bouyer 	const char *statestr;
    442       1.1  bouyer 
    443       1.1  bouyer 	szgb = ((float)size) / (1024 * 1024 * 2);	/* size in GB */
    444       1.1  bouyer 
    445       1.1  bouyer 	raid_level = prop & AMR_DRV_RAID_MASK;
    446       1.1  bouyer 
    447       1.1  bouyer 	printf("Logical volume %d\t", ldrv);
    448       1.1  bouyer 	statestr = describe_state(verbosity, state);
    449       1.1  bouyer 	printf("%s ", statestr);
    450       1.1  bouyer 	printf("(%.2f GB, RAID%d", szgb, raid_level);
    451       1.1  bouyer 	if (verbosity >= 1) {
    452       1.1  bouyer 		describe_property(prop, propstr);
    453       1.1  bouyer 		printf(" %s", propstr);
    454       1.1  bouyer 	}
    455       1.1  bouyer 	printf(")\n");
    456       1.1  bouyer }
    457       1.1  bouyer 
    458       1.1  bouyer /******************************************************************************
    459       1.1  bouyer  * Physical drives
    460       1.1  bouyer  */
    461       1.1  bouyer 
    462       1.1  bouyer void
    463       1.1  bouyer describe_one_drive(int pdrv, int verbosity, u_int8_t state)
    464       1.1  bouyer {
    465       1.1  bouyer 	const char *statestr;
    466       1.1  bouyer 
    467       1.1  bouyer 	statestr = describe_state(verbosity, state);
    468       1.1  bouyer 	if (statestr) {
    469       1.1  bouyer 		if (nschan > 0)
    470       1.1  bouyer 			printf("Physical drive %d:%d\t%s\n",
    471       1.1  bouyer 			       pdrv / AMR_MAX_NSDEVS, pdrv % AMR_MAX_NSDEVS,
    472       1.1  bouyer 			       statestr);
    473       1.1  bouyer 		else
    474       1.1  bouyer 			printf("Physical drive %d:\t%s\n", pdrv, statestr);
    475       1.1  bouyer 	}
    476       1.1  bouyer }
    477       1.1  bouyer 
    478       1.1  bouyer void
    479       1.1  bouyer describe_drive(int verbosity, int fwint, int ldrv, int sbus, int sdev)
    480       1.1  bouyer {
    481       1.1  bouyer 	int	drv, pdrv = -1;
    482       1.1  bouyer 
    483       1.1  bouyer 	if (sbus > -1 && sdev > -1)
    484       1.1  bouyer 		pdrv = (sbus * AMR_MAX_NSDEVS) + sdev;
    485       1.1  bouyer 	if (nschan != 0) {
    486       1.1  bouyer 		if (sbus > -1 && sbus >= nschan) {
    487       1.1  bouyer 			fprintf(stderr, "SCSI channel %d does not exist.\n", sbus);
    488       1.1  bouyer 			exit(1);
    489       1.1  bouyer 		} else if (sdev > -1 && sdev >= AMR_MAX_NSDEVS) {
    490       1.1  bouyer 			fprintf(stderr, "SCSI device %d:%d does not exist.\n",
    491       1.1  bouyer 				sbus, sdev);
    492       1.1  bouyer 			exit(1);
    493       1.1  bouyer 		}
    494       1.1  bouyer 	}
    495       1.1  bouyer 	if (fwint == FIRMWARE_40LD) {
    496       1.1  bouyer 		if (enq_result == AMR_STATUS_SUCCESS) {
    497       1.1  bouyer 			struct amr_enquiry3 *ae3;
    498       1.1  bouyer 
    499       1.1  bouyer 			ae3 = (struct amr_enquiry3 *)enq_buffer;
    500       1.1  bouyer 			if ((ldrv < 0 && sbus < 0) || ldrv >= 0) {
    501       1.1  bouyer 				if (ldrv >= ae3->ae_numldrives) {
    502       1.1  bouyer 					fprintf(stderr, "Logical volume %d "
    503       1.1  bouyer 						"does not exist.\n", ldrv);
    504       1.1  bouyer 					exit(1);
    505       1.1  bouyer 				}
    506       1.1  bouyer 				if (ldrv < 0) {
    507       1.1  bouyer 					for (drv = 0;
    508       1.1  bouyer 					     drv < ae3->ae_numldrives;
    509       1.1  bouyer 					     drv++)
    510       1.1  bouyer 						describe_one_volume(drv,
    511       1.1  bouyer 						    verbosity,
    512       1.1  bouyer 						    ae3->ae_drivesize[drv],
    513       1.1  bouyer 						    ae3->ae_drivestate[drv],
    514       1.1  bouyer 						    ae3->ae_driveprop[drv]);
    515       1.1  bouyer 				} else {
    516       1.1  bouyer 					describe_one_volume(ldrv,
    517       1.1  bouyer 					    verbosity,
    518       1.1  bouyer 					    ae3->ae_drivesize[ldrv],
    519       1.1  bouyer 					    ae3->ae_drivestate[ldrv],
    520       1.1  bouyer 					    ae3->ae_driveprop[ldrv]);
    521       1.1  bouyer 				}
    522       1.1  bouyer 			}
    523       1.1  bouyer 			if ((ldrv < 0 && sbus < 0) || sbus >= 0) {
    524       1.1  bouyer 				if (pdrv >= AMR_40LD_MAXPHYSDRIVES ||
    525       1.1  bouyer 				    (nschan != 0 && pdrv >= (nschan * AMR_MAX_NSDEVS))) {
    526       1.1  bouyer 					fprintf(stderr, "Physical drive %d "
    527       1.1  bouyer 						"is out of range.\n", pdrv);
    528       1.1  bouyer 					exit(1);
    529       1.1  bouyer 				}
    530       1.1  bouyer 				if (sbus < 0) {
    531       1.1  bouyer 					for (drv = 0;
    532       1.1  bouyer 					     drv < AMR_40LD_MAXPHYSDRIVES;
    533       1.1  bouyer 					     drv++) {
    534       1.1  bouyer 						if (nschan != 0 &&
    535       1.1  bouyer 						    drv >= (nschan * AMR_MAX_NSDEVS))
    536       1.1  bouyer 							break;
    537       1.1  bouyer 						describe_one_drive(drv,
    538       1.1  bouyer 						    verbosity,
    539       1.1  bouyer 						    ae3->ae_pdrivestate[drv]);
    540       1.1  bouyer 					}
    541       1.1  bouyer 				} else if (sdev < 0) {
    542       1.1  bouyer 					for (drv = sbus * AMR_MAX_NSDEVS;
    543       1.1  bouyer 					     drv < ((sbus + 1) * AMR_MAX_NSDEVS);
    544       1.1  bouyer 					     drv++) {
    545       1.1  bouyer 						if (nschan != 0 &&
    546       1.1  bouyer 						    drv >= (nschan * AMR_MAX_NSDEVS))
    547       1.1  bouyer 							break;
    548       1.1  bouyer 						describe_one_drive(drv,
    549       1.1  bouyer 						    verbosity,
    550       1.1  bouyer 						    ae3->ae_pdrivestate[drv]);
    551       1.1  bouyer 					}
    552       1.1  bouyer 				} else {
    553       1.1  bouyer 					if (nschan != 0 &&
    554       1.1  bouyer 					    pdrv < (nschan * AMR_MAX_NSDEVS))
    555       1.1  bouyer 						describe_one_drive(pdrv, 1,
    556       1.1  bouyer 						    ae3->ae_pdrivestate[pdrv]);
    557       1.1  bouyer 				}
    558       1.1  bouyer 			}
    559       1.1  bouyer 		}
    560       1.1  bouyer 	} else if (fwint == FIRMWARE_8LD) {
    561       1.1  bouyer 		/* Nothing to do here. */
    562       1.1  bouyer 		return;
    563       1.1  bouyer 	} else {
    564       1.1  bouyer 		fprintf(stderr, "Firmware interface not supported.\n");
    565       1.1  bouyer 		exit(1);
    566       1.1  bouyer 	}
    567       1.1  bouyer }
    568       1.1  bouyer 
    569       1.1  bouyer /******************************************************************************
    570       1.1  bouyer  * Main function
    571       1.1  bouyer  */
    572       1.1  bouyer 
    573       1.1  bouyer int
    574       1.1  bouyer main(int argc, char *argv[])
    575       1.1  bouyer {
    576       1.1  bouyer 	int	i;
    577       1.1  bouyer 	int	fd = -1;
    578       1.1  bouyer 	int	globalparam = 0, verbosity = 0;
    579       1.1  bouyer 	int	bflags = 0, fflags = 0, sflags = 0;
    580       1.1  bouyer 	int	lvolno = -1, physno = -1;
    581       1.1  bouyer 	int	sbusno = -1, targetno = -1;
    582       1.1  bouyer 	char	filename[MAXPATHLEN];
    583       1.1  bouyer 	char	sdev[MAXPATHLEN];
    584       1.1  bouyer 	char	*pdev;
    585       1.1  bouyer 
    586       1.1  bouyer 	extern char *optarg;
    587       1.1  bouyer 	extern int optind;
    588       1.1  bouyer 
    589       1.1  bouyer 	/*
    590       1.1  bouyer 	 * Parse arguments
    591       1.1  bouyer 	 */
    592       1.1  bouyer 	if (argc < 2)
    593       1.1  bouyer 		usage(argv[0]);
    594       1.1  bouyer 	if (strcmp(argv[1], "stat") != 0) /* only stat implemented for now */
    595       1.1  bouyer 		usage(argv[0]);
    596       1.1  bouyer 
    597       1.1  bouyer 	optind = 2;
    598       1.1  bouyer 	while ((i = getopt(argc, argv, "a:bc:f:gl:p:s:t:v")) != -1)
    599       1.1  bouyer 		switch (i) {
    600       1.1  bouyer 		case 'a':
    601       1.1  bouyer 			nattempts = atoi(optarg);
    602       1.1  bouyer 			break;
    603       1.1  bouyer 		case 'b':
    604       1.1  bouyer 			bflags++;
    605       1.1  bouyer 			break;
    606       1.1  bouyer 		case 'f':
    607       1.1  bouyer 			snprintf(filename, MAXPATHLEN, "%s", optarg);
    608       1.1  bouyer 			filename[MAXPATHLEN - 1] = '\0';
    609       1.1  bouyer 			fflags++;
    610       1.1  bouyer 			break;
    611       1.1  bouyer 		case 'g':
    612       1.1  bouyer 			globalparam = 1;
    613       1.1  bouyer 			break;
    614       1.1  bouyer 		case 'l':
    615       1.1  bouyer 			lvolno = atoi(optarg);
    616       1.1  bouyer 			break;
    617       1.1  bouyer 		case 'p':
    618       1.1  bouyer 			physno = atoi(optarg);
    619       1.1  bouyer 			break;
    620       1.1  bouyer 		case 's':
    621       1.1  bouyer 			snprintf(sdev, MAXPATHLEN, "%s", optarg);
    622       1.1  bouyer 			sdev[MAXPATHLEN - 1] = '\0';
    623       1.1  bouyer 			sflags++;
    624       1.1  bouyer 			break;
    625       1.1  bouyer 		case 't':
    626       1.1  bouyer 			sleeptime = atoi(optarg);
    627       1.1  bouyer 			break;
    628       1.1  bouyer 		case 'v':
    629       1.1  bouyer 			verbosity++;
    630       1.1  bouyer 			break;
    631       1.1  bouyer 		case '?':
    632       1.1  bouyer 		default:
    633       1.1  bouyer 			usage(argv[0]);
    634       1.1  bouyer 		}
    635       1.1  bouyer 	argc -= optind;
    636       1.1  bouyer 	argv += optind;
    637       1.1  bouyer 
    638       1.1  bouyer 	if (argc != 0)
    639       1.1  bouyer 		usage(argv[0]);
    640       1.1  bouyer 
    641       1.1  bouyer 	if (!fflags) {
    642       1.1  bouyer 		snprintf(filename, MAXPATHLEN, "/dev/amr0");
    643       1.1  bouyer 	}
    644       1.1  bouyer 
    645       1.1  bouyer 	fd = open(filename, O_RDONLY);
    646       1.1  bouyer 	if (fd == -1) {
    647       1.1  bouyer 		perror("open");
    648       1.1  bouyer 		exit(1);
    649       1.1  bouyer 	}
    650       1.1  bouyer 	if (ioctl(fd, AMR_IO_VERSION, &i) == -1) {
    651       1.1  bouyer 		perror("ioctl version");
    652       1.1  bouyer 		exit(1);
    653       1.1  bouyer 	}
    654       1.1  bouyer 
    655       1.1  bouyer 	if (sflags) {
    656       1.1  bouyer 		if(physno > -1)
    657       1.1  bouyer 			usage(argv[0]);
    658       1.1  bouyer 		else {
    659       1.1  bouyer 			sbusno = atoi(sdev);
    660       1.1  bouyer 			if ((pdev = index(sdev, ':')))
    661       1.1  bouyer 				targetno = atoi(++pdev);
    662       1.1  bouyer 		}
    663       1.1  bouyer 	} else if (physno > -1) {
    664       1.1  bouyer 		sbusno = physno / AMR_MAX_NSDEVS;
    665       1.1  bouyer 		targetno = physno % AMR_MAX_NSDEVS;
    666       1.1  bouyer 	}
    667       1.1  bouyer 
    668       1.1  bouyer 	if (globalparam && verbosity >= 1)
    669       1.1  bouyer 		printf("Version\t\t\t%d\n", i);
    670       1.1  bouyer #if 0
    671       1.1  bouyer 	if (i != 1) {
    672       1.1  bouyer 		fprintf(stderr, "Driver version (%d) not supported\n", i);
    673       1.1  bouyer 		exit(1);
    674       1.1  bouyer 	}
    675       1.1  bouyer #endif
    676       1.1  bouyer 
    677       1.1  bouyer 	i = describe_card(fd, verbosity, globalparam);
    678       1.1  bouyer 	describe_battery(fd, verbosity, i, bflags, globalparam);
    679       1.1  bouyer 	if (!bflags || lvolno > -1 || physno > -1 || sbusno > -1 || targetno > -1)
    680       1.1  bouyer 		describe_drive(verbosity, i, lvolno, sbusno, targetno);
    681       1.1  bouyer 
    682       1.1  bouyer 	return 0;
    683       1.1  bouyer }
    684