#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rf.c,v 1.38 2026/05/23 06:17:20 andvar Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/conf.h>
#include "locators.h"
#include "ioconf.h"
#include <sys/bus.h>
#include <dev/qbus/ubavar.h>
#include <sys/types.h>
#include <sys/disklabel.h>
#include <sys/disk.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/ioccom.h>
#include <sys/buf.h>
#include <sys/bufq.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <dev/qbus/rfreg.h>
#define RFS_DENS 0x0001
#define RFS_AD 0x0002
#define RFS_NOTINIT 0x0000
#define RFS_PROBING 0x0010
#define RFS_FBUF 0x0020
#define RFS_EBUF 0x0030
#define RFS_WSEC 0x0040
#define RFS_RSEC 0x0050
#define RFS_SMD 0x0060
#define RFS_RSTAT 0x0070
#define RFS_WDDS 0x0080
#define RFS_REC 0x0090
#define RFS_IDLE 0x00a0
#define RFS_CMDS 0x00f0
#define RFS_OPEN_A 0x0100
#define RFS_OPEN_B 0x0200
#define RFS_OPEN_C 0x0400
#define RFS_OPEN_MASK 0x0f00
#define RFS_OPEN_SHIFT 8
#define RFS_SETCMD(rf, state) ((rf) = ((rf) & ~RFS_CMDS) | (state))
static int rfc_match(device_t, cfdata_t, void *);
static void rfc_attach(device_t, device_t, void *);
static int rf_match(device_t, cfdata_t, void *);
static void rf_attach(device_t, device_t, void *);
static int rf_print(void *, const char *);
dev_type_open(rfopen);
dev_type_close(rfclose);
dev_type_read(rfread);
dev_type_write(rfwrite);
dev_type_ioctl(rfioctl);
dev_type_strategy(rfstrategy);
dev_type_dump(rfdump);
dev_type_size(rfsize);
const struct bdevsw rf_bdevsw = {
.d_open = rfopen,
.d_close = rfclose,
.d_strategy = rfstrategy,
.d_ioctl = rfioctl,
.d_dump = rfdump,
.d_psize = rfsize,
.d_discard = nodiscard,
.d_flag = D_DISK
};
const struct cdevsw rf_cdevsw = {
.d_open = rfopen,
.d_close = rfclose,
.d_read = rfread,
.d_write = rfwrite,
.d_ioctl = rfioctl,
.d_stop = nostop,
.d_tty = notty,
.d_poll = nopoll,
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_discard = nodiscard,
.d_flag = D_DISK
};
struct rfc_softc {
device_t sc_dev;
device_t sc_childs[2];
struct evcnt sc_intr_count;
struct buf *sc_curbuf;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmam;
void *sc_bufidx;
int sc_curchild;
int sc_bytesleft;
u_int8_t type;
};
CFATTACH_DECL_NEW(
rfc,
sizeof(struct rfc_softc),
rfc_match,
rfc_attach,
NULL,
NULL
);
struct rf_softc {
device_t sc_dev;
struct disk sc_disk;
struct rfc_softc *sc_rfc;
struct bufq_state *sc_bufq;
int sc_state;
u_int8_t sc_dnum;
};
CFATTACH_DECL_NEW(
rf,
sizeof(struct rf_softc),
rf_match,
rf_attach,
NULL,
NULL
);
struct rfc_attach_args {
u_int8_t type;
u_int8_t dnum;
};
const struct dkdriver rfdkdriver = {
.d_strategy = rfstrategy
};
int rfc_sendcmd(struct rfc_softc *, int, int, int);
struct rf_softc* get_new_buf( struct rfc_softc *);
static void rfc_intr(void *);
int
rfc_match(device_t parent, cfdata_t match, void *aux)
{
struct uba_attach_args *ua = aux;
int i;
bus_space_write_2(ua->ua_iot, ua->ua_ioh, RX2CS, RX2CS_INIT);
for (i = 0 ; i < 20 ; i++) {
if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2CS)
& RX2CS_DONE) != 0
&& (bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2ES)
& (RX2ES_RDY | RX2ES_ID)) != 0)
break;
DELAY(100000);
}
if (i >= 20)
return(0);
bus_space_write_2(ua->ua_iot, ua->ua_ioh, RX2CS,
RX2CS_RSTAT | RX2CS_IE);
for (i = 0 ; i < 20 ; i++) {
if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2CS)
& (RX2CS_DONE | RX2CS_IE)) != 0
&& (bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2ES)
& RX2ES_RDY) != 0 )
return(1);
DELAY(100000);
}
return(0);
}
#ifdef RX02_PROBE
int rfcprobedens(struct rfc_softc *, int);
int
rfcprobedens(struct rfc_softc *rfc_sc, int dnum)
{
int dens_flag;
int i;
dens_flag = 0;
do {
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS,
RX2CS_RSEC | (dens_flag == 0 ? 0 : RX2CS_DD)
| (dnum == 0 ? 0 : RX2CS_US));
DELAY(50);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_TR) == 0) {
printf("%s: did not respond to Read Sector CMD(1)\n",
device_xname(rfc_sc->sc_dev));
return(-1);
}
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2SA, 1);
DELAY(50);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_TR) == 0) {
printf("%s: did not respond to Read Sector CMD(2)\n",
device_xname(rfc_sc->sc_dev));
return(-1);
}
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2TA, 1);
for (i = 0 ; i < 200 ; i++) {
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
RX2CS) & RX2CS_DONE) != 0)
break;
DELAY(10000);
}
if (i >= 200) {
printf("%s: did not respond to Read Sector CMD(3)\n",
device_xname(rfc_sc->sc_dev));
return(-1);
}
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_ERR) == 0)
return(dens_flag);
} while (rfc_sc->type == 2 && dens_flag++ == 0);
return(-1);
}
#endif
void
rfc_attach(device_t parent, device_t self, void *aux)
{
struct rfc_softc *rfc_sc = device_private(self);
struct uba_attach_args *ua = aux;
struct rfc_attach_args rfc_aa;
int i;
rfc_sc->sc_dev = self;
rfc_sc->sc_iot = ua->ua_iot;
rfc_sc->sc_ioh = ua->ua_ioh;
rfc_sc->sc_dmat = ua->ua_dmat;
rfc_sc->sc_curbuf = NULL;
uba_intr_establish(ua->ua_icookie, ua->ua_cvec, rfc_intr, rfc_sc,
&rfc_sc->sc_intr_count);
evcnt_attach_dynamic(&rfc_sc->sc_intr_count, EVCNT_TYPE_INTR,
ua->ua_evcnt, device_xname(rfc_sc->sc_dev), "intr");
i = bus_dmamap_create(rfc_sc->sc_dmat, RX2_BYTE_DD, 1, RX2_BYTE_DD, 0,
BUS_DMA_ALLOCNOW, &rfc_sc->sc_dmam);
if (i != 0) {
printf("rfc_attach: Error creating bus dma map: %d\n", i);
return;
}
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS, RX2CS_INIT);
for (i = 0 ; i < 20 ; i++) {
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_DONE) != 0
&& (bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2ES)
& (RX2ES_RDY | RX2ES_ID)) != 0)
break;
DELAY(100000);
}
if (i >= 20) {
printf(": did not respond to INIT CMD\n");
return;
}
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_RX02) != 0) {
rfc_sc->type = 2;
rfc_aa.type = 2;
} else {
rfc_sc->type = 1;
rfc_aa.type = 1;
}
printf(": RX0%d\n", rfc_sc->type);
#ifndef RX02_PROBE
rfc_aa.dnum = 0;
rfc_sc->sc_childs[0] = config_found(rfc_sc->sc_dev, &rfc_aa, rf_print,
CFARGS_NONE);
rfc_aa.dnum = 1;
rfc_sc->sc_childs[1] = config_found(rfc_sc->sc_dev, &rfc_aa, rf_print,
CFARGS_NONE);
#else
if (rfcprobedens(rfc_sc, 0) >= 0) {
rfc_aa.dnum = 0;
rfc_sc->sc_childs[0] = config_found(rfc_sc->sc_dev, &rfc_aa,
rf_print, CFARGS_NONE);
} else
rfc_sc->sc_childs[0] = NULL;
if (rfcprobedens(rfc_sc, 1) >= 0) {
rfc_aa.dnum = 1;
rfc_sc->sc_childs[1] = config_found(rfc_sc->sc_dev, &rfc_aa,
rf_print, CFARGS_NONE);
} else
rfc_sc->sc_childs[1] = NULL;
#endif
return;
}
int
rf_match(device_t parent, cfdata_t match, void *aux)
{
struct rfc_attach_args *rfc_aa = aux;
if (match->cf_loc[RFCCF_DRIVE] == RFCCF_DRIVE_DEFAULT ||
match->cf_loc[RFCCF_DRIVE] == rfc_aa->dnum)
return(1);
return(0);
}
void
rf_attach(device_t parent, device_t self, void *aux)
{
struct rf_softc *rf_sc = device_private(self);
struct rfc_softc *rfc_sc = device_private(parent);
struct rfc_attach_args *rfc_aa = (struct rfc_attach_args *)aux;
struct disklabel *dl;
rf_sc->sc_dev = self;
rf_sc->sc_rfc = rfc_sc;
rf_sc->sc_dnum = rfc_aa->dnum;
rf_sc->sc_state = 0;
disk_init(&rf_sc->sc_disk, device_xname(rf_sc->sc_dev), &rfdkdriver);
disk_attach(&rf_sc->sc_disk);
dl = rf_sc->sc_disk.dk_label;
dl->d_type = DKTYPE_FLOPPY;
dl->d_magic = DISKMAGIC;
dl->d_magic2 = DISKMAGIC;
dl->d_typename[0] = 'R';
dl->d_typename[1] = 'X';
dl->d_typename[2] = '0';
dl->d_typename[3] = rfc_sc->type == 1 ? '1' : '2';
dl->d_typename[4] = '\0';
dl->d_secsize = DEV_BSIZE;
dl->d_nsectors = RX2_SECTORS;
dl->d_ntracks = 1;
dl->d_ncylinders = RX2_TRACKS;
dl->d_secpercyl = RX2_SECTORS;
dl->d_secperunit = RX2_SECTORS * RX2_TRACKS;
dl->d_rpm = 360;
dl->d_interleave = 1;
dl->d_npartitions = MAXPARTITIONS;
dl->d_bbsize = 0;
dl->d_sbsize = 0;
dl->d_partitions[0].p_size = 501;
dl->d_partitions[0].p_offset = 0;
dl->d_partitions[0].p_fsize = 0;
dl->d_partitions[0].p_fstype = 0;
dl->d_partitions[0].p_frag = 0;
dl->d_partitions[1].p_size = RX2_SECTORS * RX2_TRACKS / 2;
dl->d_partitions[1].p_offset = 0;
dl->d_partitions[1].p_fsize = 0;
dl->d_partitions[1].p_fstype = 0;
dl->d_partitions[1].p_frag = 0;
dl->d_partitions[2].p_size = RX2_SECTORS * RX2_TRACKS;
dl->d_partitions[2].p_offset = 0;
dl->d_partitions[2].p_fsize = 0;
dl->d_partitions[2].p_fstype = 0;
dl->d_partitions[2].p_frag = 0;
bufq_alloc(&rf_sc->sc_bufq, "disksort", BUFQ_SORT_CYLINDER);
printf("\n");
return;
}
int
rf_print(void *aux, const char *name)
{
struct rfc_attach_args *rfc_aa = aux;
if (name != NULL)
aprint_normal("RX0%d at %s", rfc_aa->type, name);
aprint_normal(" drive %d", rfc_aa->dnum);
return(UNCONF);
}
int
rfc_sendcmd(struct rfc_softc *rfc_sc, int cmd, int data1, int data2)
{
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS, cmd);
DELAY(50);
if ((cmd & RX2CS_MASK) != RX2CS_RSTAT) {
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_TR) == 0) {
printf("%s: did not respond to CMD %x (1)\n",
device_xname(rfc_sc->sc_dev), cmd);
return(-1);
}
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2DB,
data1);
}
if ((cmd & RX2CS_MASK) <= RX2CS_RSEC ||
(cmd & RX2CS_MASK) == RX2CS_WDDS) {
DELAY(50);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
& RX2CS_TR) == 0) {
printf("%s: did not respond to CMD %x (2)\n",
device_xname(rfc_sc->sc_dev), cmd);
return(-1);
}
bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2DB,
data2);
}
return(1);
}
void
rfstrategy(struct buf *buf)
{
struct rf_softc *rf_sc;
struct rfc_softc *rfc_sc;
int s;
if ((rf_sc = device_lookup_private(&rf_cd, DISKUNIT(buf->b_dev))) == NULL) {
buf->b_error = ENXIO;
biodone(buf);
return;
}
rfc_sc = rf_sc->sc_rfc;
if ((rf_sc->sc_state & (1 << (DISKPART(buf->b_dev) + RFS_OPEN_SHIFT)))
== 0)
panic("rfstrategy: can not operate on non-open drive %s "
"partition %"PRIu32, device_xname(rf_sc->sc_dev),
DISKPART(buf->b_dev));
if (buf->b_bcount == 0) {
biodone(buf);
return;
}
buf->b_rawblkno = buf->b_blkno;
s = splbio();
if (rfc_sc->sc_curbuf == NULL) {
rfc_sc->sc_curchild = rf_sc->sc_dnum;
rfc_sc->sc_curbuf = buf;
rfc_sc->sc_bufidx = buf->b_data;
rfc_sc->sc_bytesleft = buf->b_bcount;
rfc_intr(rfc_sc);
} else {
buf->b_resid = buf->b_blkno / RX2_SECTORS;
bufq_put(rf_sc->sc_bufq, buf);
buf->b_resid = 0;
}
splx(s);
}
struct rf_softc*
get_new_buf( struct rfc_softc *rfc_sc)
{
struct rf_softc *rf_sc;
struct rf_softc *other_drive;
rf_sc = device_private(rfc_sc->sc_childs[rfc_sc->sc_curchild]);
rfc_sc->sc_curbuf = bufq_get(rf_sc->sc_bufq);
if (rfc_sc->sc_curbuf != NULL) {
rfc_sc->sc_bufidx = rfc_sc->sc_curbuf->b_data;
rfc_sc->sc_bytesleft = rfc_sc->sc_curbuf->b_bcount;
} else {
RFS_SETCMD(rf_sc->sc_state, RFS_IDLE);
other_drive = device_private(
rfc_sc->sc_childs[ rfc_sc->sc_curchild == 0 ? 1 : 0]);
if (other_drive != NULL
&& bufq_peek(other_drive->sc_bufq) != NULL) {
rfc_sc->sc_curchild = rfc_sc->sc_curchild == 0 ? 1 : 0;
rf_sc = other_drive;
rfc_sc->sc_curbuf = bufq_get(rf_sc->sc_bufq);
rfc_sc->sc_bufidx = rfc_sc->sc_curbuf->b_data;
rfc_sc->sc_bytesleft = rfc_sc->sc_curbuf->b_bcount;
} else
return(NULL);
}
return(rf_sc);
}
void
rfc_intr(void *intarg)
{
struct rfc_softc *rfc_sc = intarg;
struct rf_softc *rf_sc;
int i;
rf_sc = device_private(rfc_sc->sc_childs[rfc_sc->sc_curchild]);
for (;;) {
switch (rf_sc->sc_state & RFS_CMDS) {
case RFS_PROBING:
disk_unbusy(&rf_sc->sc_disk, 0, 1);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
RX2CS) & RX2CS_ERR) == 0) {
RFS_SETCMD(rf_sc->sc_state, RFS_IDLE);
wakeup(rf_sc);
} else {
if (rfc_sc->type == 2
&& (rf_sc->sc_state & RFS_DENS) == 0
&& (rf_sc->sc_state & RFS_AD) != 0) {
rf_sc->sc_state |= RFS_DENS;
disk_busy(&rf_sc->sc_disk);
if (rfc_sendcmd(rfc_sc, RX2CS_RSEC
| RX2CS_IE | RX2CS_DD |
(rf_sc->sc_dnum == 0 ? 0 :
RX2CS_US), 1, 1) < 0) {
disk_unbusy(&rf_sc->sc_disk,
0, 1);
RFS_SETCMD(rf_sc->sc_state,
RFS_NOTINIT);
wakeup(rf_sc);
}
} else {
printf("%s: density error.\n",
device_xname(rf_sc->sc_dev));
RFS_SETCMD(rf_sc->sc_state,RFS_NOTINIT);
wakeup(rf_sc);
}
}
return;
case RFS_IDLE:
if (rfc_sc->sc_curbuf->b_bcount
% ((rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD) != 0) {
rfc_sc->sc_curbuf->b_error = EIO;
}
RFS_SETCMD(rf_sc->sc_state, (rfc_sc->sc_curbuf->b_flags
& B_READ) != 0 ? RFS_RSEC : RFS_FBUF);
break;
case RFS_RSEC:
disk_unbusy(&rf_sc->sc_disk, 0, 1);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
RX2CS) & RX2CS_ERR) != 0) {
printf("rfc_intr: Error reading sector: %x\n",
bus_space_read_2(rfc_sc->sc_iot,
rfc_sc->sc_ioh, RX2ES) );
rfc_sc->sc_curbuf->b_error = EIO;
}
RFS_SETCMD(rf_sc->sc_state, RFS_EBUF);
break;
case RFS_WSEC:
i = (rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD;
disk_unbusy(&rf_sc->sc_disk, i, 0);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
RX2CS) & RX2CS_ERR) != 0) {
printf("rfc_intr: Error writing sector: %x\n",
bus_space_read_2(rfc_sc->sc_iot,
rfc_sc->sc_ioh, RX2ES) );
rfc_sc->sc_curbuf->b_error = EIO;
break;
}
if (rfc_sc->sc_bytesleft > i) {
rfc_sc->sc_bytesleft -= i;
rfc_sc->sc_bufidx =
(char *)rfc_sc->sc_bufidx + i;
} else {
biodone(rfc_sc->sc_curbuf);
rf_sc = get_new_buf( rfc_sc);
if (rf_sc == NULL)
return;
}
RFS_SETCMD(rf_sc->sc_state,
(rfc_sc->sc_curbuf->b_flags & B_READ) != 0
? RFS_RSEC : RFS_FBUF);
break;
case RFS_FBUF:
disk_unbusy(&rf_sc->sc_disk, 0, 0);
bus_dmamap_unload(rfc_sc->sc_dmat, rfc_sc->sc_dmam);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
RX2CS) & RX2CS_ERR) != 0) {
printf("rfc_intr: Error while DMA: %x\n",
bus_space_read_2(rfc_sc->sc_iot,
rfc_sc->sc_ioh, RX2ES));
rfc_sc->sc_curbuf->b_error = EIO;
}
RFS_SETCMD(rf_sc->sc_state, RFS_WSEC);
break;
case RFS_EBUF:
i = (rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD;
disk_unbusy(&rf_sc->sc_disk, i, 1);
bus_dmamap_unload(rfc_sc->sc_dmat, rfc_sc->sc_dmam);
if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
RX2CS) & RX2CS_ERR) != 0) {
printf("rfc_intr: Error while DMA: %x\n",
bus_space_read_2(rfc_sc->sc_iot,
rfc_sc->sc_ioh, RX2ES));
rfc_sc->sc_curbuf->b_error = EIO;
break;
}
if (rfc_sc->sc_bytesleft > i) {
rfc_sc->sc_bytesleft -= i;
rfc_sc->sc_bufidx =
(char *)rfc_sc->sc_bufidx + i;
} else {
biodone(rfc_sc->sc_curbuf);
rf_sc = get_new_buf( rfc_sc);
if (rf_sc == NULL)
return;
}
RFS_SETCMD(rf_sc->sc_state,
(rfc_sc->sc_curbuf->b_flags & B_READ) != 0
? RFS_RSEC : RFS_FBUF);
break;
case RFS_NOTINIT:
case RFS_SMD:
case RFS_RSTAT:
case RFS_WDDS:
case RFS_REC:
default:
panic("Impossible state in rfc_intr(1): 0x%x\n",
rf_sc->sc_state & RFS_CMDS);
}
if (rfc_sc->sc_curbuf->b_error != 0) {
rfc_sc->sc_curbuf->b_resid = rfc_sc->sc_bytesleft;
rfc_sc->sc_curbuf->b_error = EIO;
biodone(rfc_sc->sc_curbuf);
rf_sc = get_new_buf( rfc_sc);
if (rf_sc == NULL)
return;
continue;
}
switch (rf_sc->sc_state & RFS_CMDS) {
case RFS_EBUF:
i = bus_dmamap_load(rfc_sc->sc_dmat, rfc_sc->sc_dmam,
rfc_sc->sc_bufidx, (rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD,
rfc_sc->sc_curbuf->b_proc, BUS_DMA_NOWAIT);
if (i != 0) {
printf("rfc_intr: Error loading dmamap: %d\n",
i);
rfc_sc->sc_curbuf->b_error = EIO;
break;
}
disk_busy(&rf_sc->sc_disk);
if (rfc_sendcmd(rfc_sc, RX2CS_EBUF | RX2CS_IE
| ((rf_sc->sc_state & RFS_DENS) == 0 ? 0 : RX2CS_DD)
| (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
| ((rfc_sc->sc_dmam->dm_segs[0].ds_addr
& 0x30000) >>4), ((rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD) / 2,
rfc_sc->sc_dmam->dm_segs[0].ds_addr & 0xffff) < 0) {
disk_unbusy(&rf_sc->sc_disk, 0, 1);
rfc_sc->sc_curbuf->b_error = EIO;
bus_dmamap_unload(rfc_sc->sc_dmat,
rfc_sc->sc_dmam);
}
break;
case RFS_FBUF:
i = bus_dmamap_load(rfc_sc->sc_dmat, rfc_sc->sc_dmam,
rfc_sc->sc_bufidx, (rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD,
rfc_sc->sc_curbuf->b_proc, BUS_DMA_NOWAIT);
if (i != 0) {
printf("rfc_intr: Error loading dmamap: %d\n",
i);
rfc_sc->sc_curbuf->b_error = EIO;
break;
}
disk_busy(&rf_sc->sc_disk);
if (rfc_sendcmd(rfc_sc, RX2CS_FBUF | RX2CS_IE
| ((rf_sc->sc_state & RFS_DENS) == 0 ? 0 : RX2CS_DD)
| (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
| ((rfc_sc->sc_dmam->dm_segs[0].ds_addr
& 0x30000)>>4), ((rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD) / 2,
rfc_sc->sc_dmam->dm_segs[0].ds_addr & 0xffff) < 0) {
disk_unbusy(&rf_sc->sc_disk, 0, 0);
rfc_sc->sc_curbuf->b_error = EIO;
bus_dmamap_unload(rfc_sc->sc_dmat,
rfc_sc->sc_dmam);
}
break;
case RFS_WSEC:
i = (rfc_sc->sc_curbuf->b_bcount - rfc_sc->sc_bytesleft
+ rfc_sc->sc_curbuf->b_blkno * DEV_BSIZE) /
((rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD);
if (i > RX2_TRACKS * RX2_SECTORS) {
rfc_sc->sc_curbuf->b_error = EIO;
break;
}
disk_busy(&rf_sc->sc_disk);
if (rfc_sendcmd(rfc_sc, RX2CS_WSEC | RX2CS_IE
| (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
| ((rf_sc->sc_state& RFS_DENS) == 0 ? 0 : RX2CS_DD),
i % RX2_SECTORS + 1, i / RX2_SECTORS) < 0) {
disk_unbusy(&rf_sc->sc_disk, 0, 0);
rfc_sc->sc_curbuf->b_error = EIO;
}
break;
case RFS_RSEC:
i = (rfc_sc->sc_curbuf->b_bcount - rfc_sc->sc_bytesleft
+ rfc_sc->sc_curbuf->b_blkno * DEV_BSIZE) /
((rf_sc->sc_state & RFS_DENS) == 0
? RX2_BYTE_SD : RX2_BYTE_DD);
if (i > RX2_TRACKS * RX2_SECTORS) {
rfc_sc->sc_curbuf->b_error = EIO;
break;
}
disk_busy(&rf_sc->sc_disk);
if (rfc_sendcmd(rfc_sc, RX2CS_RSEC | RX2CS_IE
| (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
| ((rf_sc->sc_state& RFS_DENS) == 0 ? 0 : RX2CS_DD),
i % RX2_SECTORS + 1, i / RX2_SECTORS) < 0) {
disk_unbusy(&rf_sc->sc_disk, 0, 1);
rfc_sc->sc_curbuf->b_error = EIO;
}
break;
case RFS_NOTINIT:
case RFS_PROBING:
case RFS_IDLE:
case RFS_SMD:
case RFS_RSTAT:
case RFS_WDDS:
case RFS_REC:
default:
panic("Impossible state in rfc_intr(2): 0x%x\n",
rf_sc->sc_state & RFS_CMDS);
}
if (rfc_sc->sc_curbuf->b_error != 0) {
rfc_sc->sc_curbuf->b_resid = rfc_sc->sc_bytesleft;
rfc_sc->sc_curbuf->b_error = EIO;
biodone(rfc_sc->sc_curbuf);
rf_sc = get_new_buf( rfc_sc);
if (rf_sc == NULL)
return;
continue;
}
break;
}
return;
}
int
rfdump(dev_t dev, daddr_t blkno, void *va, size_t size)
{
return(ENXIO);
}
int
rfsize(dev_t dev)
{
return(-1);
}
int
rfopen(dev_t dev, int oflags, int devtype, struct lwp *l)
{
struct rf_softc *rf_sc;
struct rfc_softc *rfc_sc;
struct disklabel *dl;
if ((rf_sc = device_lookup_private(&rf_cd, DISKUNIT(dev))) == NULL)
return ENXIO;
rfc_sc = rf_sc->sc_rfc;
dl = rf_sc->sc_disk.dk_label;
switch (DISKPART(dev)) {
case 0:
if ((rf_sc->sc_state & RFS_OPEN_B) != 0 )
return(ENXIO);
rf_sc->sc_state &= ~RFS_DENS;
rf_sc->sc_state &= ~RFS_AD;
rf_sc->sc_state |= RFS_OPEN_A;
break;
case 1:
if (rfc_sc->type == 1
|| (rf_sc->sc_state & RFS_OPEN_A) != 0 )
return(ENXIO);
rf_sc->sc_state |= RFS_DENS;
rf_sc->sc_state &= ~RFS_AD;
rf_sc->sc_state |= RFS_OPEN_B;
break;
case 2:
rf_sc->sc_state |= RFS_AD;
rf_sc->sc_state |= RFS_OPEN_C;
break;
default:
return(ENXIO);
break;
}
if ((rf_sc->sc_state & RFS_CMDS) == RFS_NOTINIT) {
rfc_sc->sc_curchild = rf_sc->sc_dnum;
RFS_SETCMD(rf_sc->sc_state, RFS_PROBING);
disk_busy(&rf_sc->sc_disk);
if (rfc_sendcmd(rfc_sc, RX2CS_RSEC | RX2CS_IE
| (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
| ((rf_sc->sc_state & RFS_DENS) == 0 ? 0 : RX2CS_DD),
1, 1) < 0) {
rf_sc->sc_state = 0;
return(ENXIO);
}
if (tsleep(rf_sc, PRIBIO | PCATCH, "density probe", 2 * hz)
!= 0 || (rf_sc->sc_state & RFS_CMDS) == RFS_NOTINIT) {
rf_sc->sc_state = 0;
return(ENXIO);
}
}
if ((rf_sc->sc_state & RFS_DENS) == 0) {
dl->d_nsectors = 10;
dl->d_secpercyl = 10;
dl->d_ncylinders = 50;
dl->d_secperunit = 501;
dl->d_partitions[2].p_size = 500;
} else {
dl->d_nsectors = RX2_SECTORS / 2;
dl->d_secpercyl = RX2_SECTORS / 2;
dl->d_ncylinders = RX2_TRACKS;
dl->d_secperunit = RX2_SECTORS * RX2_TRACKS / 2;
dl->d_partitions[2].p_size = RX2_SECTORS * RX2_TRACKS / 2;
}
return(0);
}
int
rfclose(dev_t dev, int fflag, int devtype, struct lwp *l)
{
struct rf_softc *rf_sc = device_lookup_private(&rf_cd, DISKUNIT(dev));
if ((rf_sc->sc_state & 1 << (DISKPART(dev) + RFS_OPEN_SHIFT)) == 0)
panic("rfclose: can not close non-open drive %s "
"partition %"PRIu32, device_xname(rf_sc->sc_dev), DISKPART(dev));
else
rf_sc->sc_state &= ~(1 << (DISKPART(dev) + RFS_OPEN_SHIFT));
if ((rf_sc->sc_state & RFS_OPEN_MASK) == 0)
rf_sc->sc_state = 0;
return(0);
}
int
rfread(dev_t dev, struct uio *uio, int ioflag)
{
return(physio(rfstrategy, NULL, dev, B_READ, minphys, uio));
}
int
rfwrite(dev_t dev, struct uio *uio, int ioflag)
{
return(physio(rfstrategy, NULL, dev, B_WRITE, minphys, uio));
}
int
rfioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l)
{
struct rf_softc *rf_sc = device_lookup_private(&rf_cd, DISKUNIT(dev));
int error;
if ((rf_sc->sc_state & 1 << (DISKPART(dev) + RFS_OPEN_SHIFT)) == 0)
panic("rfioctl: can not operate on non-open drive %s "
"partition %"PRIu32, device_xname(rf_sc->sc_dev), DISKPART(dev));
error = disk_ioctl(&rf_sc->sc_disk, dev, cmd, data, fflag, l);
if (error != EPASSTHROUGH)
return error;
switch (cmd) {
case DIOCSDINFO:
return(0);
case DIOCWDINFO:
return(0);
case DIOCRFORMAT:
break;
case DIOCWFORMAT:
break;
case DIOCSSTEP:
break;
case DIOCSRETRIES:
break;
case DIOCKLABEL:
break;
case DIOCWLABEL:
break;
break;
case DIOCEJECT:
break;
case ODIOCEJECT:
break;
case DIOCLOCK:
break;
case DIOCGDEFLABEL:
break;
case DIOCCLRLABEL:
break;
default:
return(ENOTTY);
}
return(ENOTTY);
}