Home | History | Annotate | Line # | Download | only in ic
aic7xxx_seeprom.c revision 1.1
      1 /*	$NetBSD: aic7xxx_seeprom.c,v 1.1 2000/01/26 06:04:40 thorpej Exp $	*/
      2 
      3 /*
      4  * Product specific probe and attach routines for:
      5  *      3940, 2940, aic7880, aic7870, aic7860 and aic7850 SCSI controllers
      6  *
      7  * These are the SEEPROM-reading functions only.  They were split off from
      8  * the PCI-specific support by Jason R. Thorpe <thorpej (at) netbsd.org>.
      9  *
     10  * Copyright (c) 1995, 1996 Justin T. Gibbs.
     11  * All rights reserved.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice immediately at the beginning of the file, without modification,
     18  *    this list of conditions, and the following disclaimer.
     19  * 2. Redistributions in binary form must reproduce the above copyright
     20  *    notice, this list of conditions and the following disclaimer in the
     21  *    documentation and/or other materials provided with the distribution.
     22  * 3. The name of the author may not be used to endorse or promote products
     23  *    derived from this software without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     29  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  *
     37  * from	Id: aic7870.c,v 1.37 1996/06/08 06:55:55 gibbs Exp
     38  */
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/malloc.h>
     43 #include <sys/kernel.h>
     44 #include <sys/queue.h>
     45 #include <sys/device.h>
     46 
     47 #include <machine/bus.h>
     48 #include <machine/intr.h>
     49 
     50 #include <dev/scsipi/scsi_all.h>
     51 #include <dev/scsipi/scsipi_all.h>
     52 #include <dev/scsipi/scsiconf.h>
     53 
     54 #include <dev/ic/aic7xxxreg.h>
     55 #include <dev/ic/aic7xxxvar.h>
     56 #include <dev/ic/smc93cx6var.h>
     57 
     58 /*
     59  * Under normal circumstances, these messages are unnecessary
     60  * and not terribly cosmetic.
     61  */
     62 #ifdef DEBUG
     63 #define	bootverbose	1
     64 #else
     65 #define	bootverbose	0
     66 #endif
     67 
     68 /*
     69  * Define the format of the aic78X0 SEEPROM registers (16 bits).
     70  */
     71 
     72 struct seeprom_config {
     73 
     74 /*
     75  * SCSI ID Configuration Flags
     76  */
     77 #define CFXFER		0x0007		/* synchronous transfer rate */
     78 #define CFSYNCH		0x0008		/* enable synchronous transfer */
     79 #define CFDISC		0x0010		/* enable disconnection */
     80 #define CFWIDEB		0x0020		/* wide bus device */
     81 /* UNUSED		0x00C0 */
     82 #define CFSTART		0x0100		/* send start unit SCSI command */
     83 #define CFINCBIOS	0x0200		/* include in BIOS scan */
     84 #define CFRNFOUND	0x0400		/* report even if not found */
     85 /* UNUSED		0xf800 */
     86   u_int16_t device_flags[16];	/* words 0-15 */
     87 
     88 /*
     89  * BIOS Control Bits
     90  */
     91 #define CFSUPREM	0x0001		/* support all removeable drives */
     92 #define CFSUPREMB	0x0002		/* support removeable drives for boot only */
     93 #define CFBIOSEN	0x0004		/* BIOS enabled */
     94 /* UNUSED		0x0008 */
     95 #define CFSM2DRV	0x0010		/* support more than two drives */
     96 /* UNUSED		0x0060 */
     97 #define CFEXTEND	0x0080		/* extended translation enabled */
     98 /* UNUSED		0xff00 */
     99   u_int16_t bios_control;		/* word 16 */
    100 
    101 /*
    102  * Host Adapter Control Bits
    103  */
    104 /* UNUSED		0x0001 */
    105 #define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
    106 #define CFSTERM		0x0004		/* SCSI low byte termination (non-wide cards) */
    107 #define CFWSTERM	0x0008		/* SCSI high byte termination (wide card) */
    108 #define CFSPARITY	0x0010		/* SCSI parity */
    109 /* UNUSED		0x0020 */
    110 #define CFRESETB	0x0040		/* reset SCSI bus at IC initialization */
    111 /* UNUSED		0xff80 */
    112   u_int16_t adapter_control;	/* word 17 */
    113 
    114 /*
    115  * Bus Release, Host Adapter ID
    116  */
    117 #define CFSCSIID	0x000f		/* host adapter SCSI ID */
    118 /* UNUSED		0x00f0 */
    119 #define CFBRTIME	0xff00		/* bus release time */
    120  u_int16_t brtime_id;		/* word 18 */
    121 
    122 /*
    123  * Maximum targets
    124  */
    125 #define CFMAXTARG	0x00ff	/* maximum targets */
    126 /* UNUSED		0xff00 */
    127   u_int16_t max_targets;		/* word 19 */
    128 
    129   u_int16_t res_1[11];		/* words 20-30 */
    130   u_int16_t checksum;		/* word 31 */
    131 };
    132 
    133 int ahc_acquire_seeprom __P((struct seeprom_descriptor *sd));
    134 void ahc_release_seeprom __P((struct seeprom_descriptor *sd));
    135 
    136 /*
    137  * Read the SEEPROM.  Return 0 on failure
    138  */
    139 void
    140 ahc_load_seeprom(ahc)
    141 	struct	ahc_data *ahc;
    142 {
    143 	struct	seeprom_descriptor sd;
    144 	struct	seeprom_config sc;
    145 	u_short *scarray = (u_short *)&sc;
    146 	u_short	checksum = 0;
    147 	u_char	scsi_conf;
    148 	u_char	host_id;
    149 	int	have_seeprom;
    150 
    151 	sd.sd_st = ahc->sc_st;
    152 	sd.sd_sh = ahc->sc_sh;
    153 	sd.sd_offset = SEECTL;
    154 	sd.sd_MS = SEEMS;
    155 	sd.sd_RDY = SEERDY;
    156 	sd.sd_CS = SEECS;
    157 	sd.sd_CK = SEECK;
    158 	sd.sd_DO = SEEDO;
    159 	sd.sd_DI = SEEDI;
    160 
    161 	if(bootverbose)
    162 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
    163 	have_seeprom = ahc_acquire_seeprom(&sd);
    164 	if (have_seeprom) {
    165 		have_seeprom = read_seeprom(&sd,
    166 					    (u_int16_t *)&sc,
    167 					    ahc->flags & AHC_CHNLB,
    168 					    sizeof(sc)/2);
    169 		ahc_release_seeprom(&sd);
    170 		if (have_seeprom) {
    171 			/* Check checksum */
    172 			int i;
    173 
    174 			for (i = 0;i < (sizeof(sc)/2 - 1);i = i + 1)
    175 				checksum = checksum + scarray[i];
    176 			if (checksum != sc.checksum) {
    177 				if(bootverbose)
    178 					printf ("checksum error");
    179 				have_seeprom = 0;
    180 			}
    181 			else if(bootverbose)
    182 				printf("done.\n");
    183 		}
    184 	}
    185 	if (!have_seeprom) {
    186 		if(bootverbose)
    187 			printf("\n%s: No SEEPROM availible\n", ahc_name(ahc));
    188 		ahc->flags |= AHC_USEDEFAULTS;
    189 	}
    190 	else {
    191 		/*
    192 		 * Put the data we've collected down into SRAM
    193 		 * where ahc_init will find it.
    194 		 */
    195 		int i;
    196 		int max_targ = sc.max_targets & CFMAXTARG;
    197 
    198 	        for(i = 0; i < max_targ; i++){
    199 	                u_char target_settings;
    200 			target_settings = (sc.device_flags[i] & CFXFER) << 4;
    201 			if (sc.device_flags[i] & CFSYNCH)
    202 				target_settings |= SOFS;
    203 			if (sc.device_flags[i] & CFWIDEB)
    204 				target_settings |= WIDEXFER;
    205 			if (sc.device_flags[i] & CFDISC)
    206 				ahc->discenable |= (0x01 << i);
    207 			AHC_OUTB(ahc, TARG_SCRATCH+i, target_settings);
    208 		}
    209 		AHC_OUTB(ahc, DISC_DSB, ~(ahc->discenable & 0xff));
    210 		AHC_OUTB(ahc, DISC_DSB + 1, ~((ahc->discenable >> 8) & 0xff));
    211 
    212 		host_id = sc.brtime_id & CFSCSIID;
    213 
    214 		scsi_conf = (host_id & 0x7);
    215 		if(sc.adapter_control & CFSPARITY)
    216 			scsi_conf |= ENSPCHK;
    217 		if(sc.adapter_control & CFRESETB)
    218 			scsi_conf |= RESET_SCSI;
    219 
    220 		if(ahc->type & AHC_ULTRA) {
    221 			/* Should we enable Ultra mode? */
    222 			if(!(sc.adapter_control & CFULTRAEN))
    223 				/* Treat us as a non-ultra card */
    224 				ahc->type &= ~AHC_ULTRA;
    225 		}
    226 		/* Set the host ID */
    227 		AHC_OUTB(ahc, SCSICONF, scsi_conf);
    228 		/* In case we are a wide card */
    229 		AHC_OUTB(ahc, SCSICONF + 1, host_id);
    230 	}
    231 }
    232 
    233 int
    234 ahc_acquire_seeprom(sd)
    235 	struct seeprom_descriptor *sd;
    236 {
    237 	int wait;
    238 
    239 	/*
    240 	 * Request access of the memory port.  When access is
    241 	 * granted, SEERDY will go high.  We use a 1 second
    242 	 * timeout which should be near 1 second more than
    243 	 * is needed.  Reason: after the chip reset, there
    244 	 * should be no contention.
    245 	 */
    246 	SEEPROM_OUTB(sd, sd->sd_MS);
    247 	wait = 1000;  /* 1 second timeout in msec */
    248 	while (--wait && ((SEEPROM_INB(sd) & sd->sd_RDY) == 0)) {
    249 		DELAY (1000);  /* delay 1 msec */
    250         }
    251 	if ((SEEPROM_INB(sd) & sd->sd_RDY) == 0) {
    252 		SEEPROM_OUTB(sd, 0);
    253 		return (0);
    254 	}
    255 	return(1);
    256 }
    257 
    258 void
    259 ahc_release_seeprom(sd)
    260 	struct seeprom_descriptor *sd;
    261 {
    262 	/* Release access to the memory port and the serial EEPROM. */
    263 	SEEPROM_OUTB(sd, 0);
    264 }
    265