Home | History | Annotate | Line # | Download | only in libsa
      1  1.19    isaki /*	$NetBSD: sdcd.c,v 1.19 2024/01/07 07:58:34 isaki Exp $	*/
      2   1.1  minoura 
      3   1.1  minoura /*
      4   1.1  minoura  * Copyright (c) 2001 MINOURA Makoto.
      5   1.1  minoura  * All rights reserved.
      6   1.1  minoura  *
      7   1.1  minoura  * Redistribution and use in source and binary forms, with or without
      8   1.1  minoura  * modification, are permitted provided that the following conditions
      9   1.1  minoura  * are met:
     10   1.1  minoura  * 1. Redistributions of source code must retain the above copyright
     11   1.1  minoura  *    notice, this list of conditions and the following disclaimer.
     12   1.1  minoura  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  minoura  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  minoura  *    documentation and/or other materials provided with the distribution.
     15   1.1  minoura  *
     16   1.1  minoura  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17   1.1  minoura  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18   1.1  minoura  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19   1.1  minoura  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20   1.1  minoura  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21   1.1  minoura  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22   1.1  minoura  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23   1.1  minoura  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24   1.1  minoura  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25   1.1  minoura  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26   1.1  minoura  */
     27   1.1  minoura 
     28   1.1  minoura #include <sys/param.h>
     29  1.17    isaki #include <sys/bitops.h>
     30   1.1  minoura #include <sys/disklabel.h>
     31   1.1  minoura #include <lib/libkern/libkern.h>
     32   1.1  minoura #include <lib/libsa/stand.h>
     33   1.1  minoura 
     34   1.8    isaki #include "libx68k.h"
     35   1.1  minoura #include "sdcdvar.h"
     36   1.1  minoura #include "iocs.h"
     37   1.1  minoura 
     38   1.1  minoura 
     39   1.1  minoura static int current_id = -1;
     40  1.17    isaki static int current_blkbytes;
     41  1.17    isaki static int current_blkshift;
     42  1.17    isaki static int current_devsize, current_npart;
     43   1.1  minoura static struct boot_partinfo partitions[MAXPARTITIONS];
     44   1.1  minoura 
     45  1.17    isaki static uint human2blk(uint);
     46  1.17    isaki static uint human2bsd(uint);
     47  1.17    isaki static uint bsd2blk(uint);
     48   1.1  minoura static int readdisklabel(int);
     49   1.1  minoura static int check_unit(int);
     50   1.1  minoura 
     51   1.1  minoura #ifdef DEBUG
     52   1.1  minoura #define DPRINTF(x)	printf x
     53   1.1  minoura #else
     54  1.19    isaki #define DPRINTF(x)
     55   1.1  minoura #endif
     56   1.1  minoura 
     57  1.17    isaki /*
     58  1.17    isaki  * Convert the number of sectors on Human68k
     59  1.17    isaki  * into the number of blocks on the current device.
     60  1.17    isaki  */
     61  1.17    isaki static uint
     62  1.17    isaki human2blk(uint n)
     63  1.17    isaki {
     64  1.17    isaki 	uint blk_per_sect;
     65  1.17    isaki 
     66  1.17    isaki 	/* Human68k uses 1024 byte/sector. */
     67  1.17    isaki 	blk_per_sect = 4 >> current_blkshift;
     68  1.17    isaki 	if (blk_per_sect == 0)
     69  1.17    isaki 		blk_per_sect = 1;
     70  1.17    isaki 	return blk_per_sect * n;
     71  1.17    isaki }
     72  1.17    isaki 
     73  1.17    isaki /*
     74  1.17    isaki  * Convert the number of sectors on Human68k
     75  1.17    isaki  * into the number of DEV_BSIZE sectors.
     76  1.17    isaki  */
     77  1.17    isaki static uint
     78  1.17    isaki human2bsd(uint n)
     79  1.17    isaki {
     80  1.17    isaki 
     81  1.17    isaki 	return n * (1024 / DEV_BSIZE);
     82  1.17    isaki }
     83  1.17    isaki 
     84  1.17    isaki /*
     85  1.17    isaki  * Convert the number of DEV_BSIZE sectors
     86  1.17    isaki  * into the number of blocks on the current device.
     87  1.17    isaki  */
     88  1.17    isaki static uint
     89  1.17    isaki bsd2blk(uint n)
     90  1.17    isaki {
     91  1.17    isaki 
     92  1.17    isaki 	return ((DEV_BSIZE / 256) * n) >> current_blkshift;
     93  1.17    isaki }
     94  1.17    isaki 
     95   1.1  minoura static int
     96   1.1  minoura check_unit(int id)
     97   1.1  minoura {
     98   1.1  minoura #define BUFFER_SIZE	8192
     99   1.1  minoura 	int error;
    100   1.1  minoura 	void *buffer = alloca(BUFFER_SIZE);
    101   1.1  minoura 
    102   1.1  minoura 	if (current_id == id)
    103   1.1  minoura 		return 0;
    104   1.1  minoura 
    105   1.1  minoura 	current_id = -1;
    106   1.1  minoura 
    107   1.1  minoura 	error = IOCS_S_TESTUNIT(id);
    108   1.1  minoura 	if (error < 0) {			/* not ready */
    109   1.1  minoura 		error = ENXIO;
    110   1.1  minoura 		goto out;
    111   1.1  minoura 	}
    112   1.1  minoura 
    113   1.1  minoura 	{
    114  1.15  tsutsui 		struct iocs_inquiry *inqdata = buffer;
    115   1.1  minoura 
    116  1.15  tsutsui 		error = IOCS_S_INQUIRY(sizeof(*inqdata), id, inqdata);
    117   1.1  minoura 		if (error < 0) {		/* WHY??? */
    118   1.1  minoura 			error = ENXIO;
    119   1.1  minoura 			goto out;
    120   1.1  minoura 		}
    121   1.1  minoura 		if ((inqdata->unit != 0) &&	/* direct */
    122  1.12  minoura 		    (inqdata->unit != 5) &&	/* cdrom */
    123   1.1  minoura 		    (inqdata->unit != 7)) {	/* optical */
    124   1.1  minoura 			error = EUNIT;
    125   1.1  minoura 			goto out;
    126   1.1  minoura 		}
    127   1.1  minoura 	}
    128   1.1  minoura 
    129   1.1  minoura 	{
    130   1.1  minoura 		struct iocs_readcap *rcdata = buffer;
    131   1.1  minoura 
    132   1.1  minoura 		error = IOCS_S_READCAP(id, rcdata);
    133   1.1  minoura 		if (error < 0) {		/* WHY??? */
    134   1.1  minoura 			error = EUNIT;
    135   1.1  minoura 			goto out;
    136   1.1  minoura 		}
    137  1.17    isaki 		current_blkbytes = rcdata->size;
    138  1.17    isaki 		current_blkshift = fls32(current_blkbytes) - 9;
    139   1.1  minoura 		current_devsize = rcdata->block;
    140   1.1  minoura 	}
    141   1.1  minoura 
    142   1.1  minoura 	{
    143  1.17    isaki 		error = IOCS_S_READ(0, 1, id, current_blkshift, buffer);
    144   1.1  minoura 		if (error < 0) {
    145   1.1  minoura 			error =  EIO;
    146   1.1  minoura 			goto out;
    147   1.1  minoura 		}
    148   1.7    isaki 		if (strncmp((char *)buffer, "X68SCSI1", 8) != 0) {
    149   1.1  minoura 			error = EUNLAB;
    150   1.1  minoura 			goto out;
    151   1.1  minoura 		}
    152   1.1  minoura 	}
    153   1.1  minoura 
    154   1.1  minoura  out:
    155   1.1  minoura 	return error;
    156   1.1  minoura }
    157   1.1  minoura 
    158   1.1  minoura static int
    159   1.7    isaki readdisklabel(int id)
    160   1.1  minoura {
    161   1.1  minoura 	int error, i;
    162   1.1  minoura 	char *buffer;
    163   1.1  minoura 	struct disklabel *label;
    164   1.1  minoura 	struct dos_partition *parttbl;
    165   1.1  minoura 
    166   1.1  minoura 	if (current_id == id)
    167   1.1  minoura 		return 0;
    168   1.1  minoura 	current_id = -1;
    169   1.1  minoura 
    170   1.1  minoura 	error = check_unit(id);
    171   1.1  minoura 	if (error)
    172   1.1  minoura 		return error;
    173  1.17    isaki 	if (current_blkbytes > 2048) {
    174   1.9  tsutsui 		printf("FATAL: Unsupported block size %d.\n",
    175  1.17    isaki 		    current_blkbytes);
    176   1.1  minoura 		return ERDLAB;
    177   1.1  minoura 	}
    178   1.1  minoura 
    179   1.1  minoura 	/* Try BSD disklabel first */
    180   1.1  minoura 	buffer = alloca(2048);
    181  1.17    isaki 	error = IOCS_S_READ(LABELSECTOR, 1, id, current_blkshift, buffer);
    182   1.1  minoura 	if (error < 0)
    183   1.1  minoura 		return EIO;
    184   1.7    isaki 	label = (void *)(buffer + LABELOFFSET);
    185   1.1  minoura 	if (label->d_magic == DISKMAGIC &&
    186   1.1  minoura 	    label->d_magic2 == DISKMAGIC) {
    187   1.1  minoura 		for (i = 0; i < label->d_npartitions; i++) {
    188   1.1  minoura 			partitions[i].start = label->d_partitions[i].p_offset;
    189   1.1  minoura 			partitions[i].size  = label->d_partitions[i].p_size;
    190   1.1  minoura 		}
    191   1.1  minoura 		current_npart = label->d_npartitions;
    192   1.1  minoura 
    193   1.3  minoura 		goto done;
    194   1.1  minoura 	}
    195   1.1  minoura 
    196   1.1  minoura 	/* Try Human68K-style partition table */
    197  1.17    isaki 	error = IOCS_S_READ(human2blk(2), 1, id, current_blkshift, buffer);
    198   1.1  minoura 	if (error < 0)
    199   1.1  minoura 		return EIO;
    200   1.7    isaki 	parttbl = (void *)(buffer + DOSBBSECTOR);
    201   1.7    isaki 	if (strncmp(buffer, "X68K", 4) != 0)
    202   1.1  minoura 		return EUNLAB;
    203   1.1  minoura 	parttbl++;
    204   1.1  minoura 	for (current_npart = 0, i = 0;
    205   1.1  minoura 	     current_npart < MAXPARTITIONS && i < 15 && parttbl[i].dp_size;
    206   1.1  minoura 	     i++) {
    207   1.1  minoura 		partitions[current_npart].start
    208  1.17    isaki 			= human2bsd(parttbl[i].dp_start);
    209   1.1  minoura 		partitions[current_npart].size
    210  1.17    isaki 			= human2bsd(parttbl[i].dp_size);
    211   1.1  minoura 		if (++current_npart == RAW_PART) {
    212   1.1  minoura 			partitions[current_npart].start = 0;
    213   1.1  minoura 			partitions[current_npart].size = -1; /* XXX */
    214   1.1  minoura 			current_npart++;
    215   1.1  minoura 		}
    216   1.1  minoura 	}
    217   1.3  minoura done:
    218   1.1  minoura #ifdef DEBUG
    219   1.1  minoura 	for (i = 0; i < current_npart; i++) {
    220   1.1  minoura 		printf ("%d: starts %d, size %d\n", i,
    221   1.1  minoura 			partitions[i].start,
    222   1.1  minoura 			partitions[i].size);
    223   1.1  minoura 	}
    224   1.1  minoura #endif
    225   1.1  minoura 	current_id = id;
    226   1.1  minoura 
    227   1.1  minoura 	return 0;
    228   1.1  minoura }
    229   1.1  minoura 
    230   1.1  minoura int
    231   1.7    isaki sd_getbsdpartition(int id, int humanpart)
    232   1.1  minoura {
    233   1.1  minoura 	int error, i;
    234   1.2  minoura 	char *buffer;
    235   1.2  minoura 	struct dos_partition *parttbl;
    236   1.2  minoura 	unsigned parttop;
    237   1.2  minoura 
    238   1.2  minoura 	if (humanpart < 2)
    239   1.2  minoura 		humanpart++;
    240   1.1  minoura 
    241   1.1  minoura 	error = readdisklabel(id);
    242   1.1  minoura 	if (error) {
    243   1.7    isaki 		printf("Reading disklabel: %s\n", strerror(error));
    244   1.1  minoura 		return -1;
    245   1.1  minoura 	}
    246   1.2  minoura 	buffer = alloca(2048);
    247  1.17    isaki 	error = IOCS_S_READ(human2blk(2), 1, id, current_blkshift, buffer);
    248   1.2  minoura 	if (error < 0) {
    249   1.7    isaki 		printf("Reading partition table: %s\n", strerror(error));
    250   1.2  minoura 		return -1;
    251   1.2  minoura 	}
    252   1.7    isaki 	parttbl = (void *)(buffer + DOSBBSECTOR);
    253   1.7    isaki 	if (strncmp(buffer, "X68K", 4) != 0)
    254   1.2  minoura 		return 0;
    255  1.17    isaki 	parttop = human2bsd(parttbl[humanpart].dp_start);
    256   1.1  minoura 
    257   1.1  minoura 	for (i = 0; i < current_npart; i++) {
    258   1.1  minoura 		if (partitions[i].start == parttop)
    259   1.1  minoura 			return i;
    260   1.1  minoura 	}
    261   1.1  minoura 
    262   1.7    isaki 	printf("Could not determine the boot partition.\n");
    263   1.1  minoura 
    264   1.1  minoura 	return -1;
    265   1.1  minoura }
    266   1.1  minoura 
    267   1.1  minoura struct sdcd_softc {
    268   1.1  minoura 	int			sc_part;
    269   1.1  minoura 	struct boot_partinfo	sc_partinfo;
    270   1.1  minoura };
    271   1.1  minoura 
    272   1.8    isaki /* sdopen(struct open_file *f, int id, int part) */
    273   1.1  minoura int
    274   1.8    isaki sdopen(struct open_file *f, ...)
    275   1.1  minoura {
    276   1.1  minoura 	int error;
    277   1.1  minoura 	struct sdcd_softc *sc;
    278   1.8    isaki 	int id, part;
    279   1.8    isaki 	va_list ap;
    280   1.8    isaki 
    281   1.8    isaki 	va_start(ap, f);
    282   1.8    isaki 	id   = va_arg(ap, int);
    283   1.8    isaki 	part = va_arg(ap, int);
    284   1.8    isaki 	va_end(ap);
    285   1.1  minoura 
    286   1.1  minoura 	if (id < 0 || id > 7)
    287   1.1  minoura 		return ENXIO;
    288   1.1  minoura 	if (current_id != id) {
    289   1.1  minoura 		error = readdisklabel(id);
    290   1.1  minoura 		if (error)
    291   1.1  minoura 			return error;
    292   1.1  minoura 	}
    293   1.1  minoura 	if (part >= current_npart)
    294   1.1  minoura 		return ENXIO;
    295   1.1  minoura 
    296   1.7    isaki 	sc = alloc(sizeof(struct sdcd_softc));
    297   1.1  minoura 	sc->sc_part = part;
    298   1.1  minoura 	sc->sc_partinfo = partitions[part];
    299   1.1  minoura 	f->f_devdata = sc;
    300   1.1  minoura 	return 0;
    301   1.1  minoura }
    302   1.1  minoura 
    303   1.1  minoura int
    304  1.18    isaki sdcdclose(struct open_file *f)
    305   1.1  minoura {
    306   1.9  tsutsui 
    307   1.7    isaki 	dealloc(f->f_devdata, sizeof(struct sdcd_softc));
    308   1.1  minoura 	return 0;
    309   1.1  minoura }
    310   1.1  minoura 
    311   1.1  minoura int
    312  1.18    isaki sdcdstrategy(void *arg, int rw, daddr_t dblk, size_t size,
    313   1.7    isaki            void *buf, size_t *rsize)
    314   1.1  minoura {
    315   1.1  minoura 	struct sdcd_softc *sc = arg;
    316   1.9  tsutsui 	uint32_t	start = sc->sc_partinfo.start + dblk;
    317   1.1  minoura 	size_t		nblks;
    318   1.1  minoura 	int		error;
    319   1.1  minoura 
    320   1.1  minoura 	if (size == 0) {
    321   1.1  minoura 		if (rsize)
    322   1.1  minoura 			*rsize = 0;
    323   1.1  minoura 		return 0;
    324   1.1  minoura 	}
    325  1.17    isaki 	start = bsd2blk(start);
    326  1.17    isaki 	nblks = howmany(size, current_blkbytes);
    327   1.1  minoura 
    328  1.16    isaki 	if (start < 0x200000 && nblks < 256) {
    329   1.1  minoura 		if (rw & F_WRITE)
    330   1.7    isaki 			error = IOCS_S_WRITE(start, nblks, current_id,
    331  1.17    isaki 			                     current_blkshift, buf);
    332   1.1  minoura 		else
    333   1.7    isaki 			error = IOCS_S_READ(start, nblks, current_id,
    334  1.17    isaki 			                    current_blkshift, buf);
    335   1.1  minoura 	} else {
    336   1.1  minoura 		if (rw & F_WRITE)
    337   1.7    isaki 			error = IOCS_S_WRITEEXT(start, nblks, current_id,
    338  1.17    isaki 			                        current_blkshift, buf);
    339   1.1  minoura 		else
    340   1.7    isaki 			error = IOCS_S_READEXT(start, nblks, current_id,
    341  1.17    isaki 			                       current_blkshift, buf);
    342   1.1  minoura 	}
    343   1.1  minoura 	if (error < 0)
    344   1.1  minoura 		return EIO;
    345   1.1  minoura 
    346   1.1  minoura 	if (rsize)
    347   1.1  minoura 		*rsize = size;
    348   1.1  minoura 	return 0;
    349   1.1  minoura }
    350   1.1  minoura 
    351   1.8    isaki /* cdopen(struct open_file *f, int id, int part) */
    352   1.1  minoura int
    353   1.8    isaki cdopen(struct open_file *f, ...)
    354   1.1  minoura {
    355   1.1  minoura 	int error;
    356   1.1  minoura 	struct sdcd_softc *sc;
    357   1.8    isaki 	int id, part;
    358   1.8    isaki 	va_list ap;
    359   1.8    isaki 
    360   1.8    isaki 	va_start(ap, f);
    361   1.8    isaki 	id   = va_arg(ap, int);
    362   1.8    isaki 	part = va_arg(ap, int);
    363   1.8    isaki 	va_end(ap);
    364   1.1  minoura 
    365   1.1  minoura 	if (id < 0 || id > 7)
    366   1.1  minoura 		return ENXIO;
    367  1.12  minoura 	if (part != 0 && part != 2)
    368   1.1  minoura 		return ENXIO;
    369   1.1  minoura 	if (current_id != id) {
    370   1.1  minoura 		error = check_unit(id);
    371   1.1  minoura 		if (error)
    372   1.1  minoura 			return error;
    373   1.1  minoura 	}
    374   1.1  minoura 
    375   1.7    isaki 	sc = alloc(sizeof(struct sdcd_softc));
    376   1.1  minoura 	current_npart = 3;
    377   1.1  minoura 	sc->sc_part = 0;
    378  1.14  tsutsui 	sc->sc_partinfo.start = 0;
    379  1.10      mrg 	sc->sc_partinfo.size = current_devsize;
    380   1.1  minoura 	f->f_devdata = sc;
    381  1.12  minoura 	current_id = id;
    382  1.12  minoura 
    383   1.1  minoura 	return 0;
    384   1.1  minoura }
    385