Home | History | Annotate | Line # | Download | only in libtos
diskio.c revision 1.1.8.2
      1 /*	$NetBSD: diskio.c,v 1.1.8.2 2002/03/16 15:56:58 jdolecek Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Waldi Ravens.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *        This product includes software developed by Waldi Ravens.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/types.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <ctype.h>
     37 #include <stdio.h>
     38 #include <xhdi.h>
     39 #include "libtos.h"
     40 #include "diskio.h"
     41 #include "ahdilbl.h"
     42 #include <osbind.h>
     43 
     44 struct pun_info {
     45 	u_int16_t	puns;
     46 	u_int8_t	pun[16];
     47 	u_int32_t	part_start[16];
     48 	u_int32_t	P_cookie;
     49 	u_int32_t	*P_cookptr;
     50 	u_int16_t	P_version;
     51 	u_int16_t	P_max_sector;
     52 	u_int32_t	reserved[16];
     53 };
     54 
     55 static char *	strbd    PROTO((char *, ...));
     56 static int	setmami  PROTO((disk_t *, char *));
     57 static int	setnames PROTO((disk_t *));
     58 static int	setsizes PROTO((disk_t *));
     59 static int	ahdi_compatible PROTO((void));
     60 
     61 disk_t *
     62 disk_open(name)
     63 	char	*name;
     64 {
     65 	disk_t	*dd;
     66 
     67 	dd = xmalloc(sizeof *dd);
     68 	memset(dd, 0, sizeof *dd);
     69 
     70 	if (setmami(dd, name) || setnames(dd) || setsizes(dd)) {
     71 		disk_close(dd);
     72 		return(NULL);
     73 	}
     74 	return(dd);
     75 }
     76 
     77 void
     78 disk_close(dd)
     79 	disk_t	*dd;
     80 {
     81 	if (dd) {
     82 		free(dd->product);
     83 		free(dd->sname);
     84 		free(dd->fname);
     85 		if (dd->xtra_info != NULL)
     86 			free(dd->xtra_info);
     87 		free(dd);
     88 	}
     89 }
     90 
     91 void *
     92 disk_read(dd, start, count)
     93 	disk_t	*dd;
     94 	u_int	start,
     95 		count;
     96 {
     97 	char	*buffer;
     98 	int	bdev;
     99 	long	e;
    100 
    101 	buffer = xmalloc(count * dd->bsize);
    102 
    103 	e = XHReadWrite(dd->major, dd->minor, 0, start, count, buffer);
    104 	if (!e)
    105 		return(buffer);
    106 	if (e == -32 || (e == -1 && XHGetVersion() == -1)) {
    107 		if (!ahdi_compatible())
    108 		    fatal(-1, "AHDI 3.0 compatible harddisk driver required");
    109 		bdev = BIOSDEV(dd->major, dd->minor);
    110 		if (bdev && !bios_read(buffer, start, count, bdev))
    111 			return(buffer);
    112 	}
    113 
    114 	free(buffer);
    115 	return(NULL);
    116 }
    117 
    118 int
    119 disk_write(dd, start, count, buffer)
    120 	disk_t	*dd;
    121 	u_int	start,
    122 		count;
    123 	void	*buffer;
    124 {
    125 	int	bdev;
    126 	long	e;
    127 
    128 	e = XHReadWrite(dd->major, dd->minor, 1, start, count, buffer);
    129 	if (e == -32 || (e == -1 && XHGetVersion() == -1)) {
    130 		if (!ahdi_compatible())
    131 		    fatal(-1, "AHDI 3.0 compatible harddisk driver required");
    132 		bdev = BIOSDEV(dd->major, dd->minor);
    133 		if (bdev)
    134 			e = bios_write(buffer, start, count, bdev);
    135 	}
    136 
    137 	return((int)e);
    138 }
    139 
    140 static int
    141 ahdi_compatible()
    142 {
    143 	static int	ahdi_compat;
    144 
    145 	if (!ahdi_compat) {
    146 		long		oldsp = Super(0L);
    147 		struct pun_info	*punp = *((struct pun_info **)0x0516);
    148 		(void)Super(oldsp);
    149 		if (punp && punp->P_cookie == 0x41484449
    150 				&& punp->P_cookptr == &punp->P_cookie
    151 				&& punp->P_version >= 0x0300)
    152 			ahdi_compat = 1;
    153 	}
    154 	return(ahdi_compat);
    155 }
    156 
    157 static int
    158 setmami(dd, name)
    159 	disk_t	*dd;
    160 	char	*name;
    161 {
    162 	char	*p = name;
    163 	u_int	target, lun;
    164 	bus_t	bus;
    165 
    166 	if (*p == 'i') {
    167 		bus = IDE;
    168 		if (*++p < '0' || *p > '1') {
    169 			if (*p)
    170 			    error(-1, "%s: invalid IDE target `%c'", name, *p);
    171 			else
    172 			    error(-1, "%s: missing IDE target", name);
    173 			return(-1);
    174 		}
    175 		target = *p++ - '0';
    176 		lun = 0;
    177 	} else {
    178 		char	*b;
    179 
    180 		if (*p == 'a') {
    181 			bus = ACSI;
    182 			b = "ACSI";
    183 		} else if (*p == 's') {
    184 			bus = SCSI;
    185 			b = "SCSI";
    186 		} else {
    187 			error(-1, "%s: invalid DISK argument", name);
    188 			return(-1);
    189 		}
    190 		if (*++p < '0' || *p > '7') {
    191 			if (*p)
    192 				error(-1, "%s: invalid %s target `%c'", name,
    193 									b, *p);
    194 			else
    195 				error(-1, "%s: missing %s target", name, b);
    196 			return(-1);
    197 		}
    198 		target = *p++ - '0';
    199 
    200 		if (*p < '0' || *p > '7') {
    201 			if (*p) {
    202 				error(-1, "%s: invalid %s lun `%c'", name,
    203 								     b, *p);
    204 				return(-1);
    205 			}
    206 			lun = 0;
    207 		} else
    208 			lun = *p++ - '0';
    209 	}
    210 	if (*p) {
    211 		error(-1, "%s: invalid DISK argument", name);
    212 		return(-1);
    213 	}
    214 	dd->major = MAJOR(bus, target, lun);
    215 	dd->minor = MINOR(bus, target, lun);
    216 	return(0);
    217 }
    218 
    219 static int
    220 setnames(dd)
    221 	disk_t	*dd;
    222 {
    223 	char	sn[16], us[16], ls[16], *bs;
    224 	int	b, u, l;
    225 
    226 	b = BUS(dd->major, dd->minor);
    227 	u = TARGET(dd->major, dd->minor);
    228 	l = LUN(dd->major, dd->minor);
    229 
    230 	switch (b) {
    231 	case IDE:	bs = "IDE";
    232 			break;
    233 	case ACSI:	bs = "ACSI";
    234 			break;
    235 	case SCSI:	bs = "SCSI";
    236 			break;
    237 	default:	error(-1, "invalid bus no. %d", b);
    238 			return(-1);
    239 	}
    240 
    241 	if (u < 0 || u > 7 || (b == IDE && u > 1)) {
    242 		error(-1, "invalid %s target `%d'", bs, u);
    243 		return(-1);
    244 	}
    245 	sprintf(us, " target %d", u);
    246 
    247 	if (l < 0 || l > 7 || (b == IDE && l > 0)) {
    248 		error(-1, "invalid %s lun `%d'", bs, l);
    249 		return(-1);
    250 	}
    251 	if (b == IDE) {
    252 		sprintf(sn, "i%d", u);
    253 		ls[0] = '\0';
    254 	} else {
    255 		sprintf(sn, "%c%d%d", tolower(*bs), u, l);
    256 		sprintf(ls, " lun %d", l);
    257 	}
    258 
    259 	dd->fname = strbd(bs, us, ls, NULL);
    260 	dd->sname = strbd(sn, NULL);
    261 	return(0);
    262 }
    263 
    264 static int
    265 setsizes(dd)
    266 	disk_t	*dd;
    267 {
    268 	if (XHGetVersion() != -1) {
    269 	    char	*p, prod[1024];
    270 
    271 	    if (XHInqTarget2(dd->major, dd->minor, &dd->bsize, NULL, prod,
    272 								sizeof(prod))) {
    273 		if (XHInqTarget(dd->major, dd->minor, &dd->bsize, NULL, prod)) {
    274 			error(-1, "%s: device not configured", dd->sname);
    275 			return(-1);
    276 		}
    277 	    }
    278 	    p = strrchr(prod, '\0');
    279 	    while (isspace(*--p))
    280 		*p = '\0';
    281 	    dd->product = strbd(prod, NULL);
    282 	    if (!XHGetCapacity(dd->major, dd->minor, &dd->msize, &dd->bsize))
    283 		return(0);
    284 	} else {
    285 	    dd->product = strbd("unknown", NULL);
    286 	    dd->bsize = AHDI_BSIZE;		/* XXX */
    287 	}
    288 
    289 	/* Trial&error search for last sector on medium */
    290 	{
    291 		u_int	u, l, m;
    292 		void	*p, (*oldvec)();
    293 
    294 		/* turn off etv_critic handler */
    295 		oldvec = Setexc(257, bios_critic);
    296 
    297 		u = (u_int)-2; l = 0;
    298 		while (u != l) {
    299 			m = l + ((u - l + 1) / 2);
    300 			p = disk_read(dd, m, 1);
    301 			free(p);
    302 			if (p == NULL)
    303 				u = m - 1;
    304 			else
    305 				l = m;
    306 		}
    307 
    308 		/* turn on etv_critic handler */
    309 		(void)Setexc(257, oldvec);
    310 
    311 		if (l) {
    312 			dd->msize = l + 1;
    313 			return(0);
    314 		}
    315 		error(-1, "%s: device not configured", dd->sname);
    316 		return(-1);
    317 	}
    318 }
    319 
    320 static char *
    321 strbd(string1)
    322 	char	*string1;
    323 {
    324 	char		*p, *result;
    325 	size_t		length = 1;
    326 	va_list		ap;
    327 
    328 	va_start(ap, string1);
    329 	for (p = string1; p; p = va_arg(ap, char *))
    330 		length += strlen(p);
    331 	va_end(ap);
    332 
    333 	*(result = xmalloc(length)) = '\0';
    334 
    335 	va_start(ap, string1);
    336 	for (p = string1; p; p = va_arg(ap, char *))
    337 		strcat(result, p);
    338 	va_end(ap);
    339 
    340 	return(result);
    341 }
    342