Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/sandpoint/stand/netboot - add IDE/SATA diskboot fac...
details: https://anonhg.NetBSD.org/src/rev/d0a231508325
branches: trunk
changeset: 755892:d0a231508325
user: phx <phx%NetBSD.org@localhost>
date: Sat Jun 26 22:13:32 2010 +0000
description:
- add IDE/SATA diskboot facility
known ok with KuroBox PCIIDE, need more debug on SiI3512 SATA
which fails reading sectors from a drive.
- now capable of TFTP loading
Code submitted by Toru Nishimura.
diffstat:
sys/arch/sandpoint/stand/netboot/dsk.c | 570 +++++++++++++++++++++++++++++++++
1 files changed, 570 insertions(+), 0 deletions(-)
diffs (truncated from 574 to 300 lines):
diff -r 4a08be10ec2c -r d0a231508325 sys/arch/sandpoint/stand/netboot/dsk.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/sandpoint/stand/netboot/dsk.c Sat Jun 26 22:13:32 2010 +0000
@@ -0,0 +1,570 @@
+/* $NetBSD: dsk.c,v 1.1 2010/06/26 22:13:32 phx Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * assumptions;
+ * - up to 4 IDE/SATA drives.
+ * - a single (master) drive in each IDE channel.
+ * - all drives are up and spinning.
+ */
+
+#include <sys/types.h>
+
+#include <lib/libsa/stand.h>
+#include <lib/libsa/ufs.h>
+
+#include <sys/disklabel.h>
+#include <sys/bootblock.h>
+
+#include <machine/bootinfo.h>
+#include <machine/stdarg.h>
+
+#include "globals.h"
+
+/*
+ * - no vtophys() translation, vaddr_t == paddr_t.
+ */
+#define CSR_READ_4(r) in32rb(r)
+#define CSR_WRITE_4(r,v) out32rb(r,v)
+#define CSR_READ_1(r) *(volatile uint8_t *)(r)
+#define CSR_WRITE_1(r,v) *(volatile uint8_t *)(r)=(v)
+
+#define DSK_DECL(xxx) \
+ int xxx ## _match(unsigned, void *); \
+ void * xxx ## _init(unsigned, void *)
+
+DSK_DECL(pciide);
+DSK_DECL(siisata);
+
+struct dskdv {
+ char *name;
+ int (*match)(unsigned, void *);
+ void *(*init)(unsigned, void *);
+ void *priv;
+};
+
+static struct dskdv ldskdv[] = {
+ { "pciide", pciide_match, pciide_init, },
+ { "siisata", siisata_match, siisata_init, },
+};
+static int ndskdv = sizeof(ldskdv)/sizeof(ldskdv[0]);
+
+static int probe_drive(struct dkdev_ata *, int);
+static void drive_ident(struct disk *, char *);
+static char *mkident(char *, int);
+static void set_xfermode(struct dkdev_ata *, int);
+static void decode_dlabel(struct disk *, char *);
+static int sii_spinwait_irqack(struct dkdev_ata *, int);
+static int lba_read(struct disk *, uint64_t, uint32_t, void *);
+static void issue48(struct dvata_chan *, uint64_t, uint32_t);
+static void issue28(struct dvata_chan *, uint64_t, uint32_t);
+static struct disk *lookup_disk(int);
+
+static struct disk ldisk[4];
+
+int
+dskdv_init(unsigned tag, void **cookie)
+{
+ struct dskdv *dv;
+ int n;
+
+ for (n = 0; n < ndskdv; n++) {
+ dv = &ldskdv[n];
+ if ((*dv->match)(tag, NULL) > 0)
+ goto found;
+ }
+ return 0;
+ found:
+ dv->priv = (*dv->init)(tag, NULL);
+ *cookie = dv;
+ return 1;
+}
+
+int
+disk_scan(void *cookie)
+{
+ struct dskdv *dv = cookie;
+ struct dkdev_ata *l = dv->priv;
+ struct disk *d;
+ int n, ndrive;
+
+ ndrive = 0;
+ for (n = 0; n < 4; n++) {
+ if (l->presense[n] == 0)
+ continue;
+ if (probe_drive(l, n) == 0) {
+ l->presense[n] = 0;
+ continue;
+ }
+ d = &ldisk[ndrive];
+ d->dvops = l;
+ d->unittag = ndrive;
+ snprintf(d->xname, sizeof(d->xname), "wd%d", d->unittag);
+ drive_ident(d, l->iobuf);
+ decode_dlabel(d, l->iobuf);
+ set_xfermode(l, n);
+ ndrive += 1;
+ }
+ return ndrive;
+}
+
+int
+spinwait_unbusy(struct dkdev_ata *l, int n, int milli, const char **err)
+{
+ struct dvata_chan *chan = &l->chan[n];
+ int sts;
+ const char *msg;
+
+ sts = CSR_READ_1(chan->cmd + _STS);
+ while (milli-- > 0 && sts != 0xff && (sts & ATA_STS_BUSY)) {
+ delay(1000);
+ sts = CSR_READ_1(chan->cmd + _STS);
+ }
+ msg = NULL;
+ if (sts == 0xff)
+ msg = "returned 0xff";
+ else if (sts & ATA_STS_ERR)
+ msg = "returned ERR";
+ else if (sts & ATA_STS_BUSY)
+ msg = "remains BUSY";
+
+ if (err != NULL)
+ *err = msg;
+ return (msg == NULL);
+}
+
+int
+perform_atareset(struct dkdev_ata *l, int n)
+{
+ struct dvata_chan *chan = &l->chan[n];
+
+ CSR_WRITE_1(chan->ctl, ATA_DREQ);
+ delay(10);
+ CSR_WRITE_1(chan->ctl, ATA_SRST|ATA_DREQ);
+ delay(10);
+ CSR_WRITE_1(chan->ctl, ATA_DREQ);
+
+ return spinwait_unbusy(l, n, 150, NULL);
+}
+
+int
+satapresense(struct dkdev_ata *l, int n)
+{
+#define VND_CH(n) (((n&02)<<8)+((n&01)<<7))
+#define VND_SC(n) (0x100+VND_CH(n))
+#define VND_SS(n) (0x104+VND_CH(n))
+
+ uint32_t sc = l->bar[5] + VND_SC(n);
+ uint32_t ss = l->bar[5] + VND_SS(n);
+ unsigned val;
+
+ val = (00 << 4) | (03 << 8); /* any speed, no pwrmgt */
+ CSR_WRITE_4(sc, val | 01); /* perform init */
+ delay(50 * 1000);
+ CSR_WRITE_4(sc, val);
+ delay(50 * 1000);
+ val = CSR_READ_4(ss); /* has completed */
+ return ((val & 03) == 03); /* active drive found */
+}
+
+static int
+probe_drive(struct dkdev_ata *l, int n)
+{
+ struct dvata_chan *chan = &l->chan[n];
+ uint16_t *p;
+ int i;
+
+ CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_IDENT);
+ (void)CSR_READ_1(chan->alt);
+ delay(10 * 1000);
+ if (spinwait_unbusy(l, n, 1000, NULL) == 0)
+ return 0;
+
+ p = (uint16_t *)l->iobuf;
+ for (i = 0; i < 512; i += 2) {
+ /* need to have bswap16 */
+ *p++ = iole16toh(chan->cmd + _DAT);
+ }
+ (void)CSR_READ_1(chan->cmd + _STS);
+ return 1;
+}
+
+static void
+drive_ident(struct disk *d, char *ident)
+{
+ uint16_t *p;
+ uint64_t huge;
+
+ p = (uint16_t *)ident;
+#if 1
+ printf("[49]%04x [82]%04x [83]%04x [84]%04x "
+ "[85]%04x [86]%04x [87]%04x [88]%04x\n",
+ p[49], p[82], p[83], p[84],
+ p[85], p[86], p[87], p[88]);
+#endif
+ huge = 0;
+ printf("%s: ", d->xname);
+ printf("<%s> ", mkident((char *)ident + 54, 40));
+ if (p[49] & (1 << 8))
+ printf("DMA ");
+ if (p[49] & (1 << 9)) {
+ printf("LBA ");
+ huge = p[60] | (p[61] << 16);
+ }
+ if ((p[83] & 0xc000) == 0x4000 && (p[83] & (1 << 10))) {
+ huge = p[100] | (p[101] << 16);
+ huge |= (uint64_t)p[102] << 32;
+ huge |= (uint64_t)p[103] << 48;
+ printf("LBA48 ");
+ }
+ huge >>= (1 + 10);
+ printf("%d MB\n", (int)huge);
+
+ memcpy(d->ident, ident, sizeof(d->ident));
+ d->nsect = huge;
+ d->lba_read = lba_read;
+}
+
+static char *
+mkident(char *src, int len)
+{
+ static char local[40];
+ char *dst, *end, *last;
+
+ if (len > sizeof(local))
+ len = sizeof(local);
+ dst = last = local;
+ end = src + len - 1;
+
+ /* reserve space for '\0' */
+ if (len < 2)
+ goto out;
+ /* skip leading white space */
+ while (*src != '\0' && src < end && *src == ' ')
+ ++src;
+ /* copy string, omitting trailing white space */
+ while (*src != '\0' && src < end) {
+ *dst++ = *src;
+ if (*src++ != ' ')
+ last = dst;
+ }
+ out:
+ *last = '\0';
+ return local;
+}
+
+static void
+decode_dlabel(struct disk *d, char *iobuf)
+{
+ struct mbr_partition *mp, *bsdp;
+ struct disklabel *dlp;
+ struct partition *pp;
+ char *dp;
+ int i, first;
+
+ bsdp = NULL;
+ (*d->lba_read)(d, 0, 1, iobuf);
+ if (bswap16(*(uint16_t *)(iobuf + MBR_MAGIC_OFFSET)) != MBR_MAGIC)
+ goto skip;
Home |
Main Index |
Thread Index |
Old Index