1*38ad5e0eSandvar /* $NetBSD: rf.c,v 1.37 2021/08/12 19:53:18 andvar Exp $ */
2281464ebSragge /*
3281464ebSragge * Copyright (c) 2002 Jochen Kunz.
4281464ebSragge * All rights reserved.
5281464ebSragge *
6281464ebSragge * Redistribution and use in source and binary forms, with or without
7281464ebSragge * modification, are permitted provided that the following conditions
8281464ebSragge * are met:
9281464ebSragge * 1. Redistributions of source code must retain the above copyright
10281464ebSragge * notice, this list of conditions and the following disclaimer.
11281464ebSragge * 2. Redistributions in binary form must reproduce the above copyright
12281464ebSragge * notice, this list of conditions and the following disclaimer in the
13281464ebSragge * documentation and/or other materials provided with the distribution.
14281464ebSragge * 3. The name of Jochen Kunz may not be used to endorse or promote
15281464ebSragge * products derived from this software without specific prior
16281464ebSragge * written permission.
17281464ebSragge *
18281464ebSragge * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ
19281464ebSragge * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20281464ebSragge * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21281464ebSragge * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOCHEN KUNZ
22281464ebSragge * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23281464ebSragge * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24281464ebSragge * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25281464ebSragge * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26281464ebSragge * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27281464ebSragge * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28281464ebSragge * POSSIBILITY OF SUCH DAMAGE.
29281464ebSragge */
30281464ebSragge
31281464ebSragge /*
32281464ebSragge TODO:
33281464ebSragge - Better LBN bound checking, block padding for SD disks.
349876532dSwiz - Formatting / "Set Density"
356dc8db11Sryoon - Better error handling / detailed error reason reporting.
36281464ebSragge */
37281464ebSragge
38365cbd94Slukem #include <sys/cdefs.h>
39*38ad5e0eSandvar __KERNEL_RCSID(0, "$NetBSD: rf.c,v 1.37 2021/08/12 19:53:18 andvar Exp $");
40365cbd94Slukem
41281464ebSragge /* autoconfig stuff */
42281464ebSragge #include <sys/param.h>
43281464ebSragge #include <sys/device.h>
44281464ebSragge #include <sys/conf.h>
45281464ebSragge #include "locators.h"
46281464ebSragge #include "ioconf.h"
47281464ebSragge
48281464ebSragge /* bus_space / bus_dma */
49a2a38285Sad #include <sys/bus.h>
50281464ebSragge
51281464ebSragge /* UniBus / QBus specific stuff */
52281464ebSragge #include <dev/qbus/ubavar.h>
53281464ebSragge
54281464ebSragge /* disk interface */
55281464ebSragge #include <sys/types.h>
56281464ebSragge #include <sys/disklabel.h>
57281464ebSragge #include <sys/disk.h>
58281464ebSragge
59281464ebSragge /* general system data and functions */
60281464ebSragge #include <sys/systm.h>
61281464ebSragge #include <sys/ioctl.h>
62281464ebSragge #include <sys/ioccom.h>
63281464ebSragge
64281464ebSragge /* physio / buffer handling */
65281464ebSragge #include <sys/buf.h>
6605f25dccSyamt #include <sys/bufq.h>
67281464ebSragge
68281464ebSragge /* tsleep / sleep / wakeup */
69281464ebSragge #include <sys/proc.h>
70281464ebSragge /* hz for above */
71281464ebSragge #include <sys/kernel.h>
72281464ebSragge
73281464ebSragge /* bit definitions for RX211 */
74281464ebSragge #include <dev/qbus/rfreg.h>
75281464ebSragge
76281464ebSragge
77281464ebSragge #define RFS_DENS 0x0001 /* single or double density */
78281464ebSragge #define RFS_AD 0x0002 /* density auto detect */
79281464ebSragge #define RFS_NOTINIT 0x0000 /* not initialized */
80281464ebSragge #define RFS_PROBING 0x0010 /* density detect / verify started */
81281464ebSragge #define RFS_FBUF 0x0020 /* Fill Buffer */
82281464ebSragge #define RFS_EBUF 0x0030 /* Empty Buffer */
83281464ebSragge #define RFS_WSEC 0x0040 /* Write Sector */
84281464ebSragge #define RFS_RSEC 0x0050 /* Read Sector */
85281464ebSragge #define RFS_SMD 0x0060 /* Set Media Density */
86281464ebSragge #define RFS_RSTAT 0x0070 /* Read Status */
87281464ebSragge #define RFS_WDDS 0x0080 /* Write Deleted Data Sector */
88281464ebSragge #define RFS_REC 0x0090 /* Read Error Code */
89281464ebSragge #define RFS_IDLE 0x00a0 /* controller is idle */
90281464ebSragge #define RFS_CMDS 0x00f0 /* command mask */
91c049e276Sragge #define RFS_OPEN_A 0x0100 /* partition a open */
92c049e276Sragge #define RFS_OPEN_B 0x0200 /* partition b open */
93c049e276Sragge #define RFS_OPEN_C 0x0400 /* partition c open */
94c049e276Sragge #define RFS_OPEN_MASK 0x0f00 /* mask for open partitions */
95c049e276Sragge #define RFS_OPEN_SHIFT 8 /* to shift 1 to get RFS_OPEN_A */
96281464ebSragge #define RFS_SETCMD(rf, state) ((rf) = ((rf) & ~RFS_CMDS) | (state))
97281464ebSragge
98281464ebSragge
99281464ebSragge
100281464ebSragge /* autoconfig stuff */
101dfba8166Smatt static int rfc_match(device_t, cfdata_t, void *);
102dfba8166Smatt static void rfc_attach(device_t, device_t, void *);
103dfba8166Smatt static int rf_match(device_t, cfdata_t, void *);
104dfba8166Smatt static void rf_attach(device_t, device_t, void *);
105281464ebSragge static int rf_print(void *, const char *);
106281464ebSragge
1079876532dSwiz /* device interface functions / interface to disk(9) */
108281464ebSragge dev_type_open(rfopen);
109281464ebSragge dev_type_close(rfclose);
110281464ebSragge dev_type_read(rfread);
111281464ebSragge dev_type_write(rfwrite);
112281464ebSragge dev_type_ioctl(rfioctl);
113281464ebSragge dev_type_strategy(rfstrategy);
114281464ebSragge dev_type_dump(rfdump);
115281464ebSragge dev_type_size(rfsize);
116281464ebSragge
117281464ebSragge
118281464ebSragge /* Entries in block and character major device number switch table. */
119281464ebSragge const struct bdevsw rf_bdevsw = {
120a68f9396Sdholland .d_open = rfopen,
121a68f9396Sdholland .d_close = rfclose,
122a68f9396Sdholland .d_strategy = rfstrategy,
123a68f9396Sdholland .d_ioctl = rfioctl,
124a68f9396Sdholland .d_dump = rfdump,
125a68f9396Sdholland .d_psize = rfsize,
1268c70ef39Sdholland .d_discard = nodiscard,
127a68f9396Sdholland .d_flag = D_DISK
128281464ebSragge };
129281464ebSragge
130281464ebSragge const struct cdevsw rf_cdevsw = {
131a68f9396Sdholland .d_open = rfopen,
132a68f9396Sdholland .d_close = rfclose,
133a68f9396Sdholland .d_read = rfread,
134a68f9396Sdholland .d_write = rfwrite,
135a68f9396Sdholland .d_ioctl = rfioctl,
136a68f9396Sdholland .d_stop = nostop,
137a68f9396Sdholland .d_tty = notty,
138a68f9396Sdholland .d_poll = nopoll,
139a68f9396Sdholland .d_mmap = nommap,
140a68f9396Sdholland .d_kqfilter = nokqfilter,
141f9228f42Sdholland .d_discard = nodiscard,
142a68f9396Sdholland .d_flag = D_DISK
143281464ebSragge };
144281464ebSragge
145281464ebSragge
146281464ebSragge
147281464ebSragge struct rfc_softc {
148dfba8166Smatt device_t sc_dev; /* common device data */
149dfba8166Smatt device_t sc_childs[2]; /* child devices */
150281464ebSragge struct evcnt sc_intr_count; /* Interrupt counter for statistics */
151281464ebSragge struct buf *sc_curbuf; /* buf that is currently in work */
1529876532dSwiz bus_space_tag_t sc_iot; /* bus_space I/O tag */
1539876532dSwiz bus_space_handle_t sc_ioh; /* bus_space I/O handle */
154281464ebSragge bus_dma_tag_t sc_dmat; /* bus_dma DMA tag */
155281464ebSragge bus_dmamap_t sc_dmam; /* bus_dma DMA map */
15653524e44Schristos void *sc_bufidx; /* current position in buffer data */
157281464ebSragge int sc_curchild; /* child whos bufq is in work */
158281464ebSragge int sc_bytesleft; /* bytes left to transfer */
159281464ebSragge u_int8_t type; /* controller type, 1 or 2 */
160281464ebSragge };
161281464ebSragge
162281464ebSragge
163281464ebSragge
164dfba8166Smatt CFATTACH_DECL_NEW(
165281464ebSragge rfc,
166281464ebSragge sizeof(struct rfc_softc),
167281464ebSragge rfc_match,
168281464ebSragge rfc_attach,
169281464ebSragge NULL,
170281464ebSragge NULL
171281464ebSragge );
172281464ebSragge
173281464ebSragge
174281464ebSragge
175281464ebSragge struct rf_softc {
176dfba8166Smatt device_t sc_dev; /* common device data */
177281464ebSragge struct disk sc_disk; /* common disk device data */
178dfba8166Smatt struct rfc_softc *sc_rfc; /* our parent */
179aec75b1cSyamt struct bufq_state *sc_bufq; /* queue of pending transfers */
180281464ebSragge int sc_state; /* state of drive */
181281464ebSragge u_int8_t sc_dnum; /* drive number, 0 or 1 */
182281464ebSragge };
183281464ebSragge
184281464ebSragge
185281464ebSragge
186dfba8166Smatt CFATTACH_DECL_NEW(
187281464ebSragge rf,
188281464ebSragge sizeof(struct rf_softc),
189281464ebSragge rf_match,
190281464ebSragge rf_attach,
191281464ebSragge NULL,
192281464ebSragge NULL
193281464ebSragge );
194281464ebSragge
195281464ebSragge
196281464ebSragge
197281464ebSragge struct rfc_attach_args {
198281464ebSragge u_int8_t type; /* controller type, 1 or 2 */
199281464ebSragge u_int8_t dnum; /* drive number, 0 or 1 */
200281464ebSragge };
201281464ebSragge
202281464ebSragge
203281464ebSragge
204dfba8166Smatt const struct dkdriver rfdkdriver = {
2056f00c789Smlelstv .d_strategy = rfstrategy
206281464ebSragge };
207281464ebSragge
208281464ebSragge
209281464ebSragge
210281464ebSragge /* helper functions */
211281464ebSragge int rfc_sendcmd(struct rfc_softc *, int, int, int);
212c049e276Sragge struct rf_softc* get_new_buf( struct rfc_softc *);
213281464ebSragge static void rfc_intr(void *);
214281464ebSragge
215281464ebSragge
216281464ebSragge
217281464ebSragge /*
218281464ebSragge * Issue a reset command to the controller and look for the bits in
219281464ebSragge * RX2CS and RX2ES.
220281464ebSragge * RX2CS_RX02 and / or RX2CS_DD can be set,
221281464ebSragge * RX2ES has to be set, all other bits must be 0
222281464ebSragge */
223281464ebSragge int
rfc_match(device_t parent,cfdata_t match,void * aux)224dfba8166Smatt rfc_match(device_t parent, cfdata_t match, void *aux)
225281464ebSragge {
226281464ebSragge struct uba_attach_args *ua = aux;
227281464ebSragge int i;
228281464ebSragge
229281464ebSragge /* Issue reset command. */
230281464ebSragge bus_space_write_2(ua->ua_iot, ua->ua_ioh, RX2CS, RX2CS_INIT);
231281464ebSragge /* Wait for the controller to become ready, that is when
232281464ebSragge * RX2CS_DONE, RX2ES_RDY and RX2ES_ID are set. */
233281464ebSragge for (i = 0 ; i < 20 ; i++) {
234281464ebSragge if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2CS)
235281464ebSragge & RX2CS_DONE) != 0
236281464ebSragge && (bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2ES)
237281464ebSragge & (RX2ES_RDY | RX2ES_ID)) != 0)
238281464ebSragge break;
239281464ebSragge DELAY(100000); /* wait 100ms */
240281464ebSragge }
241281464ebSragge /*
242281464ebSragge * Give up if the timeout has elapsed
243281464ebSragge * and the controller is not ready.
244281464ebSragge */
245281464ebSragge if (i >= 20)
246281464ebSragge return(0);
247281464ebSragge /*
248281464ebSragge * Issue a Read Status command with interrupt enabled.
249281464ebSragge * The uba(4) driver wants to catch the interrupt to get the
250281464ebSragge * interrupt vector and level of the device
251281464ebSragge */
252281464ebSragge bus_space_write_2(ua->ua_iot, ua->ua_ioh, RX2CS,
253281464ebSragge RX2CS_RSTAT | RX2CS_IE);
254281464ebSragge /*
255281464ebSragge * Wait for command to finish, ignore errors and
256281464ebSragge * abort if the controller does not respond within the timeout
257281464ebSragge */
258281464ebSragge for (i = 0 ; i < 20 ; i++) {
259281464ebSragge if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2CS)
260281464ebSragge & (RX2CS_DONE | RX2CS_IE)) != 0
261281464ebSragge && (bus_space_read_2(ua->ua_iot, ua->ua_ioh, RX2ES)
262281464ebSragge & RX2ES_RDY) != 0 )
263281464ebSragge return(1);
264281464ebSragge DELAY(100000); /* wait 100ms */
265281464ebSragge }
266281464ebSragge return(0);
267281464ebSragge }
268281464ebSragge
269281464ebSragge
270281464ebSragge
271281464ebSragge /* #define RX02_PROBE 1 */
272281464ebSragge #ifdef RX02_PROBE
273281464ebSragge /*
274281464ebSragge * Probe the density of an inserted floppy disk.
275281464ebSragge * This is done by reading a sector from disk.
276281464ebSragge * Return -1 on error, 0 on SD and 1 on DD.
277281464ebSragge */
278281464ebSragge int rfcprobedens(struct rfc_softc *, int);
279281464ebSragge int
rfcprobedens(struct rfc_softc * rfc_sc,int dnum)280281464ebSragge rfcprobedens(struct rfc_softc *rfc_sc, int dnum)
281281464ebSragge {
282281464ebSragge int dens_flag;
283281464ebSragge int i;
284281464ebSragge
285281464ebSragge dens_flag = 0;
286281464ebSragge do {
287281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS,
288281464ebSragge RX2CS_RSEC | (dens_flag == 0 ? 0 : RX2CS_DD)
289281464ebSragge | (dnum == 0 ? 0 : RX2CS_US));
290281464ebSragge /*
291281464ebSragge * Transfer request set?
292281464ebSragge * Wait 50us, the controller needs this time to setle
293281464ebSragge */
294281464ebSragge DELAY(50);
295281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
296281464ebSragge & RX2CS_TR) == 0) {
297281464ebSragge printf("%s: did not respond to Read Sector CMD(1)\n",
298dfba8166Smatt device_xname(rfc_sc->sc_dev));
299281464ebSragge return(-1);
300281464ebSragge }
301281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2SA, 1);
302281464ebSragge /* Wait 50us, the controller needs this time to setle */
303281464ebSragge DELAY(50);
304281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
305281464ebSragge & RX2CS_TR) == 0) {
306281464ebSragge printf("%s: did not respond to Read Sector CMD(2)\n",
307dfba8166Smatt device_xname(rfc_sc->sc_dev));
308281464ebSragge return(-1);
309281464ebSragge }
310281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2TA, 1);
311281464ebSragge /* Wait for the command to finish */
312281464ebSragge for (i = 0 ; i < 200 ; i++) {
313281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
314281464ebSragge RX2CS) & RX2CS_DONE) != 0)
315281464ebSragge break;
316281464ebSragge DELAY(10000); /* wait 10ms */
317281464ebSragge }
318281464ebSragge if (i >= 200) {
319281464ebSragge printf("%s: did not respond to Read Sector CMD(3)\n",
320dfba8166Smatt device_xname(rfc_sc->sc_dev));
321281464ebSragge return(-1);
322281464ebSragge }
323281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
324281464ebSragge & RX2CS_ERR) == 0)
325281464ebSragge return(dens_flag);
326281464ebSragge } while (rfc_sc->type == 2 && dens_flag++ == 0);
327281464ebSragge return(-1);
328281464ebSragge }
329281464ebSragge #endif /* RX02_PROBE */
330281464ebSragge
331281464ebSragge
332281464ebSragge
333281464ebSragge void
rfc_attach(device_t parent,device_t self,void * aux)334dfba8166Smatt rfc_attach(device_t parent, device_t self, void *aux)
335281464ebSragge {
336ceb94256Sthorpej struct rfc_softc *rfc_sc = device_private(self);
337281464ebSragge struct uba_attach_args *ua = aux;
338281464ebSragge struct rfc_attach_args rfc_aa;
339281464ebSragge int i;
340281464ebSragge
341dfba8166Smatt rfc_sc->sc_dev = self;
342281464ebSragge rfc_sc->sc_iot = ua->ua_iot;
343281464ebSragge rfc_sc->sc_ioh = ua->ua_ioh;
344281464ebSragge rfc_sc->sc_dmat = ua->ua_dmat;
345281464ebSragge rfc_sc->sc_curbuf = NULL;
346281464ebSragge /* Tell the QBus busdriver about our interrupt handler. */
347281464ebSragge uba_intr_establish(ua->ua_icookie, ua->ua_cvec, rfc_intr, rfc_sc,
348281464ebSragge &rfc_sc->sc_intr_count);
349281464ebSragge /* Attach to the interrupt counter, see evcnt(9) */
350281464ebSragge evcnt_attach_dynamic(&rfc_sc->sc_intr_count, EVCNT_TYPE_INTR,
351dfba8166Smatt ua->ua_evcnt, device_xname(rfc_sc->sc_dev), "intr");
352281464ebSragge /* get a bus_dma(9) handle */
353281464ebSragge i = bus_dmamap_create(rfc_sc->sc_dmat, RX2_BYTE_DD, 1, RX2_BYTE_DD, 0,
354281464ebSragge BUS_DMA_ALLOCNOW, &rfc_sc->sc_dmam);
355281464ebSragge if (i != 0) {
356c049e276Sragge printf("rfc_attach: Error creating bus dma map: %d\n", i);
357281464ebSragge return;
358281464ebSragge }
359281464ebSragge
360281464ebSragge /* Issue reset command. */
361281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS, RX2CS_INIT);
362281464ebSragge /*
363281464ebSragge * Wait for the controller to become ready, that is when
364281464ebSragge * RX2CS_DONE, RX2ES_RDY and RX2ES_ID are set.
365281464ebSragge */
366281464ebSragge for (i = 0 ; i < 20 ; i++) {
367281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
368281464ebSragge & RX2CS_DONE) != 0
369281464ebSragge && (bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2ES)
370281464ebSragge & (RX2ES_RDY | RX2ES_ID)) != 0)
371281464ebSragge break;
372281464ebSragge DELAY(100000); /* wait 100ms */
373281464ebSragge }
374281464ebSragge /*
375281464ebSragge * Give up if the timeout has elapsed
376281464ebSragge * and the controller is not ready.
377281464ebSragge */
378281464ebSragge if (i >= 20) {
379281464ebSragge printf(": did not respond to INIT CMD\n");
380281464ebSragge return;
381281464ebSragge }
382281464ebSragge /* Is ths a RX01 or a RX02? */
383281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
384281464ebSragge & RX2CS_RX02) != 0) {
385281464ebSragge rfc_sc->type = 2;
386281464ebSragge rfc_aa.type = 2;
387281464ebSragge } else {
388281464ebSragge rfc_sc->type = 1;
389281464ebSragge rfc_aa.type = 1;
390281464ebSragge }
391281464ebSragge printf(": RX0%d\n", rfc_sc->type);
392281464ebSragge
393281464ebSragge #ifndef RX02_PROBE
394281464ebSragge /*
395*38ad5e0eSandvar * Both disk drives and the controller are one physical unit.
396*38ad5e0eSandvar * If we found the controller, there will be both disk drives.
397281464ebSragge * So attach them.
398281464ebSragge */
399281464ebSragge rfc_aa.dnum = 0;
4002685996bSthorpej rfc_sc->sc_childs[0] = config_found(rfc_sc->sc_dev, &rfc_aa, rf_print,
401c7fb772bSthorpej CFARGS_NONE);
402281464ebSragge rfc_aa.dnum = 1;
4032685996bSthorpej rfc_sc->sc_childs[1] = config_found(rfc_sc->sc_dev, &rfc_aa, rf_print,
404c7fb772bSthorpej CFARGS_NONE);
405281464ebSragge #else /* RX02_PROBE */
406281464ebSragge /*
407281464ebSragge * There are clones of the DEC RX system with standard shugart
408281464ebSragge * interface. In this case we can not be sure that there are
409*38ad5e0eSandvar * both disk drives. So we want to do a detection of attached
410281464ebSragge * drives. This is done by reading a sector from disk. This means
4119876532dSwiz * that there must be a formatted disk in the drive at boot time.
412281464ebSragge * This is bad, but I did not find another way to detect the
413281464ebSragge * (non)existence of a floppy drive.
414281464ebSragge */
415281464ebSragge if (rfcprobedens(rfc_sc, 0) >= 0) {
416281464ebSragge rfc_aa.dnum = 0;
417cbab9cadSchs rfc_sc->sc_childs[0] = config_found(rfc_sc->sc_dev, &rfc_aa,
418c7fb772bSthorpej rf_print, CFARGS_NONE);
419281464ebSragge } else
420281464ebSragge rfc_sc->sc_childs[0] = NULL;
421281464ebSragge if (rfcprobedens(rfc_sc, 1) >= 0) {
422281464ebSragge rfc_aa.dnum = 1;
423cbab9cadSchs rfc_sc->sc_childs[1] = config_found(rfc_sc->sc_dev, &rfc_aa,
424c7fb772bSthorpej rf_print, CFARGS_NONE);
425281464ebSragge } else
426281464ebSragge rfc_sc->sc_childs[1] = NULL;
427281464ebSragge #endif /* RX02_PROBE */
428281464ebSragge return;
429281464ebSragge }
430281464ebSragge
431281464ebSragge
432281464ebSragge
433281464ebSragge int
rf_match(device_t parent,cfdata_t match,void * aux)434dfba8166Smatt rf_match(device_t parent, cfdata_t match, void *aux)
435281464ebSragge {
436281464ebSragge struct rfc_attach_args *rfc_aa = aux;
437281464ebSragge
438281464ebSragge /*
439281464ebSragge * Only attach if the locator is wildcarded or
440281464ebSragge * if the specified locator addresses the current device.
441281464ebSragge */
442281464ebSragge if (match->cf_loc[RFCCF_DRIVE] == RFCCF_DRIVE_DEFAULT ||
443281464ebSragge match->cf_loc[RFCCF_DRIVE] == rfc_aa->dnum)
444281464ebSragge return(1);
445281464ebSragge return(0);
446281464ebSragge }
447281464ebSragge
448281464ebSragge
449281464ebSragge
450281464ebSragge void
rf_attach(device_t parent,device_t self,void * aux)451dfba8166Smatt rf_attach(device_t parent, device_t self, void *aux)
452281464ebSragge {
453ceb94256Sthorpej struct rf_softc *rf_sc = device_private(self);
454dfba8166Smatt struct rfc_softc *rfc_sc = device_private(parent);
455281464ebSragge struct rfc_attach_args *rfc_aa = (struct rfc_attach_args *)aux;
456281464ebSragge struct disklabel *dl;
457281464ebSragge
458dfba8166Smatt rf_sc->sc_dev = self;
459dfba8166Smatt rf_sc->sc_rfc = rfc_sc;
460281464ebSragge rf_sc->sc_dnum = rfc_aa->dnum;
461281464ebSragge rf_sc->sc_state = 0;
462dfba8166Smatt disk_init(&rf_sc->sc_disk, device_xname(rf_sc->sc_dev), &rfdkdriver);
463281464ebSragge disk_attach(&rf_sc->sc_disk);
464281464ebSragge dl = rf_sc->sc_disk.dk_label;
465c182898bSchristos dl->d_type = DKTYPE_FLOPPY; /* drive type */
466281464ebSragge dl->d_magic = DISKMAGIC; /* the magic number */
467281464ebSragge dl->d_magic2 = DISKMAGIC;
468281464ebSragge dl->d_typename[0] = 'R';
469281464ebSragge dl->d_typename[1] = 'X';
470281464ebSragge dl->d_typename[2] = '0';
471281464ebSragge dl->d_typename[3] = rfc_sc->type == 1 ? '1' : '2'; /* type name */
472281464ebSragge dl->d_typename[4] = '\0';
473281464ebSragge dl->d_secsize = DEV_BSIZE; /* bytes per sector */
474281464ebSragge /*
475*38ad5e0eSandvar * Fill in some values to have an initialized data structure. Some
476281464ebSragge * values will be reset by rfopen() depending on the actual density.
477281464ebSragge */
478281464ebSragge dl->d_nsectors = RX2_SECTORS; /* sectors per track */
479281464ebSragge dl->d_ntracks = 1; /* tracks per cylinder */
480281464ebSragge dl->d_ncylinders = RX2_TRACKS; /* cylinders per unit */
481281464ebSragge dl->d_secpercyl = RX2_SECTORS; /* sectors per cylinder */
482281464ebSragge dl->d_secperunit = RX2_SECTORS * RX2_TRACKS; /* sectors per unit */
483281464ebSragge dl->d_rpm = 360; /* rotational speed */
484281464ebSragge dl->d_interleave = 1; /* hardware sector interleave */
485281464ebSragge /* number of partitions in following */
486281464ebSragge dl->d_npartitions = MAXPARTITIONS;
487281464ebSragge dl->d_bbsize = 0; /* size of boot area at sn0, bytes */
488281464ebSragge dl->d_sbsize = 0; /* max size of fs superblock, bytes */
489281464ebSragge /* number of sectors in partition */
490281464ebSragge dl->d_partitions[0].p_size = 501;
491281464ebSragge dl->d_partitions[0].p_offset = 0; /* starting sector */
492281464ebSragge dl->d_partitions[0].p_fsize = 0; /* fs basic fragment size */
493281464ebSragge dl->d_partitions[0].p_fstype = 0; /* fs type */
494281464ebSragge dl->d_partitions[0].p_frag = 0; /* fs fragments per block */
495281464ebSragge dl->d_partitions[1].p_size = RX2_SECTORS * RX2_TRACKS / 2;
496281464ebSragge dl->d_partitions[1].p_offset = 0; /* starting sector */
497281464ebSragge dl->d_partitions[1].p_fsize = 0; /* fs basic fragment size */
498281464ebSragge dl->d_partitions[1].p_fstype = 0; /* fs type */
499281464ebSragge dl->d_partitions[1].p_frag = 0; /* fs fragments per block */
500281464ebSragge dl->d_partitions[2].p_size = RX2_SECTORS * RX2_TRACKS;
501281464ebSragge dl->d_partitions[2].p_offset = 0; /* starting sector */
502281464ebSragge dl->d_partitions[2].p_fsize = 0; /* fs basic fragment size */
503281464ebSragge dl->d_partitions[2].p_fstype = 0; /* fs type */
504281464ebSragge dl->d_partitions[2].p_frag = 0; /* fs fragments per block */
505aec75b1cSyamt bufq_alloc(&rf_sc->sc_bufq, "disksort", BUFQ_SORT_CYLINDER);
506281464ebSragge printf("\n");
507281464ebSragge return;
508281464ebSragge }
509281464ebSragge
510281464ebSragge
511281464ebSragge
512281464ebSragge int
rf_print(void * aux,const char * name)513281464ebSragge rf_print(void *aux, const char *name)
514281464ebSragge {
515281464ebSragge struct rfc_attach_args *rfc_aa = aux;
516281464ebSragge
517281464ebSragge if (name != NULL)
518281464ebSragge aprint_normal("RX0%d at %s", rfc_aa->type, name);
519281464ebSragge aprint_normal(" drive %d", rfc_aa->dnum);
520281464ebSragge return(UNCONF);
521281464ebSragge }
522281464ebSragge
523281464ebSragge
524281464ebSragge
525281464ebSragge /* Send a command to the controller */
526281464ebSragge int
rfc_sendcmd(struct rfc_softc * rfc_sc,int cmd,int data1,int data2)527281464ebSragge rfc_sendcmd(struct rfc_softc *rfc_sc, int cmd, int data1, int data2)
528281464ebSragge {
529281464ebSragge
530281464ebSragge /* Write command to CSR. */
531281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS, cmd);
532281464ebSragge /* Wait 50us, the controller needs this time to setle. */
533281464ebSragge DELAY(50);
534281464ebSragge /* Write parameter 1 to DBR */
5352e741b3aSchristos if ((cmd & RX2CS_MASK) != RX2CS_RSTAT) {
536281464ebSragge /* Transfer request set? */
537281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
538281464ebSragge & RX2CS_TR) == 0) {
539281464ebSragge printf("%s: did not respond to CMD %x (1)\n",
540dfba8166Smatt device_xname(rfc_sc->sc_dev), cmd);
541281464ebSragge return(-1);
542281464ebSragge }
543281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2DB,
544281464ebSragge data1);
545281464ebSragge }
546281464ebSragge /* Write parameter 2 to DBR */
5472e741b3aSchristos if ((cmd & RX2CS_MASK) <= RX2CS_RSEC ||
5482e741b3aSchristos (cmd & RX2CS_MASK) == RX2CS_WDDS) {
549281464ebSragge /* Wait 50us, the controller needs this time to setle. */
550281464ebSragge DELAY(50);
551281464ebSragge /* Transfer request set? */
552281464ebSragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2CS)
553281464ebSragge & RX2CS_TR) == 0) {
554281464ebSragge printf("%s: did not respond to CMD %x (2)\n",
555dfba8166Smatt device_xname(rfc_sc->sc_dev), cmd);
556281464ebSragge return(-1);
557281464ebSragge }
558281464ebSragge bus_space_write_2(rfc_sc->sc_iot, rfc_sc->sc_ioh, RX2DB,
559281464ebSragge data2);
560281464ebSragge }
561281464ebSragge return(1);
562281464ebSragge }
563281464ebSragge
564281464ebSragge
565281464ebSragge
566281464ebSragge void
rfstrategy(struct buf * buf)567281464ebSragge rfstrategy(struct buf *buf)
568281464ebSragge {
569281464ebSragge struct rf_softc *rf_sc;
570281464ebSragge struct rfc_softc *rfc_sc;
571dfba8166Smatt int s;
572281464ebSragge
573dfba8166Smatt if ((rf_sc = device_lookup_private(&rf_cd, DISKUNIT(buf->b_dev))) == NULL) {
574281464ebSragge buf->b_error = ENXIO;
575281464ebSragge biodone(buf);
576281464ebSragge return;
577281464ebSragge }
578dfba8166Smatt rfc_sc = rf_sc->sc_rfc;
5799876532dSwiz /* We are going to operate on a non-open dev? PANIC! */
580dfba8166Smatt if ((rf_sc->sc_state & (1 << (DISKPART(buf->b_dev) + RFS_OPEN_SHIFT)))
581c049e276Sragge == 0)
582c049e276Sragge panic("rfstrategy: can not operate on non-open drive %s "
58323efc364Scegger "partition %"PRIu32, device_xname(rf_sc->sc_dev),
584c049e276Sragge DISKPART(buf->b_dev));
585281464ebSragge if (buf->b_bcount == 0) {
586281464ebSragge biodone(buf);
587281464ebSragge return;
588281464ebSragge }
589281464ebSragge /*
59070de9736Syamt * bufq_put() operates on b_rawblkno. rfstrategy() gets
591281464ebSragge * only b_blkno that is partition relative. As a floppy does not
592281464ebSragge * have partitions b_rawblkno == b_blkno.
593281464ebSragge */
594281464ebSragge buf->b_rawblkno = buf->b_blkno;
595281464ebSragge /*
596281464ebSragge * from sys/kern/subr_disk.c:
597281464ebSragge * Seek sort for disks. We depend on the driver which calls us using
598281464ebSragge * b_resid as the current cylinder number.
599281464ebSragge */
600dfba8166Smatt s = splbio();
601281464ebSragge if (rfc_sc->sc_curbuf == NULL) {
602281464ebSragge rfc_sc->sc_curchild = rf_sc->sc_dnum;
603281464ebSragge rfc_sc->sc_curbuf = buf;
604e36a3212Sjoerg rfc_sc->sc_bufidx = buf->b_data;
605281464ebSragge rfc_sc->sc_bytesleft = buf->b_bcount;
606281464ebSragge rfc_intr(rfc_sc);
607281464ebSragge } else {
608281464ebSragge buf->b_resid = buf->b_blkno / RX2_SECTORS;
60970de9736Syamt bufq_put(rf_sc->sc_bufq, buf);
610c049e276Sragge buf->b_resid = 0;
611281464ebSragge }
612dfba8166Smatt splx(s);
613281464ebSragge }
614281464ebSragge
615c049e276Sragge /*
616c049e276Sragge * Look if there is another buffer in the bufferqueue of this drive
617c049e276Sragge * and start to process it if there is one.
618c049e276Sragge * If the bufferqueue is empty, look at the bufferqueue of the other drive
619c049e276Sragge * that is attached to this controller.
620*38ad5e0eSandvar * Start processing the bufferqueue of the other drive if it isn't empty.
621c049e276Sragge * Return a pointer to the softc structure of the drive that is now
622c049e276Sragge * ready to process a buffer or NULL if there is no buffer in either queues.
623c049e276Sragge */
624c049e276Sragge struct rf_softc*
get_new_buf(struct rfc_softc * rfc_sc)625c049e276Sragge get_new_buf( struct rfc_softc *rfc_sc)
626c049e276Sragge {
627c049e276Sragge struct rf_softc *rf_sc;
628c049e276Sragge struct rf_softc *other_drive;
629c049e276Sragge
6306827de95Sjkunz rf_sc = device_private(rfc_sc->sc_childs[rfc_sc->sc_curchild]);
63170de9736Syamt rfc_sc->sc_curbuf = bufq_get(rf_sc->sc_bufq);
632c049e276Sragge if (rfc_sc->sc_curbuf != NULL) {
633e36a3212Sjoerg rfc_sc->sc_bufidx = rfc_sc->sc_curbuf->b_data;
634c049e276Sragge rfc_sc->sc_bytesleft = rfc_sc->sc_curbuf->b_bcount;
635c049e276Sragge } else {
636c049e276Sragge RFS_SETCMD(rf_sc->sc_state, RFS_IDLE);
6376827de95Sjkunz other_drive = device_private(
6386827de95Sjkunz rfc_sc->sc_childs[ rfc_sc->sc_curchild == 0 ? 1 : 0]);
639c049e276Sragge if (other_drive != NULL
64070de9736Syamt && bufq_peek(other_drive->sc_bufq) != NULL) {
641c049e276Sragge rfc_sc->sc_curchild = rfc_sc->sc_curchild == 0 ? 1 : 0;
642c049e276Sragge rf_sc = other_drive;
64370de9736Syamt rfc_sc->sc_curbuf = bufq_get(rf_sc->sc_bufq);
644e36a3212Sjoerg rfc_sc->sc_bufidx = rfc_sc->sc_curbuf->b_data;
645c049e276Sragge rfc_sc->sc_bytesleft = rfc_sc->sc_curbuf->b_bcount;
646c049e276Sragge } else
647c049e276Sragge return(NULL);
648c049e276Sragge }
649c049e276Sragge return(rf_sc);
650c049e276Sragge }
651c049e276Sragge
652c049e276Sragge
653c049e276Sragge
654281464ebSragge void
rfc_intr(void * intarg)655281464ebSragge rfc_intr(void *intarg)
656281464ebSragge {
657281464ebSragge struct rfc_softc *rfc_sc = intarg;
658281464ebSragge struct rf_softc *rf_sc;
659281464ebSragge int i;
660281464ebSragge
6616827de95Sjkunz rf_sc = device_private(rfc_sc->sc_childs[rfc_sc->sc_curchild]);
662bc2387e2Sdsl for (;;) {
663281464ebSragge /*
664281464ebSragge * First clean up from previous command...
665281464ebSragge */
666281464ebSragge switch (rf_sc->sc_state & RFS_CMDS) {
667281464ebSragge case RFS_PROBING: /* density detect / verify started */
668281464ebSragge disk_unbusy(&rf_sc->sc_disk, 0, 1);
669c049e276Sragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
670c049e276Sragge RX2CS) & RX2CS_ERR) == 0) {
671281464ebSragge RFS_SETCMD(rf_sc->sc_state, RFS_IDLE);
672281464ebSragge wakeup(rf_sc);
673281464ebSragge } else {
674281464ebSragge if (rfc_sc->type == 2
675281464ebSragge && (rf_sc->sc_state & RFS_DENS) == 0
676281464ebSragge && (rf_sc->sc_state & RFS_AD) != 0) {
677281464ebSragge /* retry at DD */
678281464ebSragge rf_sc->sc_state |= RFS_DENS;
679281464ebSragge disk_busy(&rf_sc->sc_disk);
680c049e276Sragge if (rfc_sendcmd(rfc_sc, RX2CS_RSEC
681c049e276Sragge | RX2CS_IE | RX2CS_DD |
682c049e276Sragge (rf_sc->sc_dnum == 0 ? 0 :
683c049e276Sragge RX2CS_US), 1, 1) < 0) {
684c049e276Sragge disk_unbusy(&rf_sc->sc_disk,
685c049e276Sragge 0, 1);
686281464ebSragge RFS_SETCMD(rf_sc->sc_state,
687281464ebSragge RFS_NOTINIT);
688281464ebSragge wakeup(rf_sc);
689281464ebSragge }
690281464ebSragge } else {
691281464ebSragge printf("%s: density error.\n",
692dfba8166Smatt device_xname(rf_sc->sc_dev));
693281464ebSragge RFS_SETCMD(rf_sc->sc_state,RFS_NOTINIT);
694281464ebSragge wakeup(rf_sc);
695281464ebSragge }
696281464ebSragge }
697281464ebSragge return;
698281464ebSragge case RFS_IDLE: /* controller is idle */
699281464ebSragge if (rfc_sc->sc_curbuf->b_bcount
700281464ebSragge % ((rf_sc->sc_state & RFS_DENS) == 0
701281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD) != 0) {
702281464ebSragge /*
703c049e276Sragge * can only handle blocks that are a multiple
704c049e276Sragge * of the physical block size
705281464ebSragge */
70666fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
707281464ebSragge }
708281464ebSragge RFS_SETCMD(rf_sc->sc_state, (rfc_sc->sc_curbuf->b_flags
709281464ebSragge & B_READ) != 0 ? RFS_RSEC : RFS_FBUF);
710281464ebSragge break;
711281464ebSragge case RFS_RSEC: /* Read Sector */
712281464ebSragge disk_unbusy(&rf_sc->sc_disk, 0, 1);
713281464ebSragge /* check for errors */
714c049e276Sragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
715c049e276Sragge RX2CS) & RX2CS_ERR) != 0) {
716281464ebSragge /* should do more verbose error reporting */
717c049e276Sragge printf("rfc_intr: Error reading secotr: %x\n",
718281464ebSragge bus_space_read_2(rfc_sc->sc_iot,
719281464ebSragge rfc_sc->sc_ioh, RX2ES) );
72066fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
721281464ebSragge }
722281464ebSragge RFS_SETCMD(rf_sc->sc_state, RFS_EBUF);
723281464ebSragge break;
724281464ebSragge case RFS_WSEC: /* Write Sector */
725281464ebSragge i = (rf_sc->sc_state & RFS_DENS) == 0
726281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD;
727281464ebSragge disk_unbusy(&rf_sc->sc_disk, i, 0);
728281464ebSragge /* check for errors */
729c049e276Sragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
730c049e276Sragge RX2CS) & RX2CS_ERR) != 0) {
731281464ebSragge /* should do more verbose error reporting */
732c049e276Sragge printf("rfc_intr: Error writing secotr: %x\n",
733281464ebSragge bus_space_read_2(rfc_sc->sc_iot,
734281464ebSragge rfc_sc->sc_ioh, RX2ES) );
73566fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
736281464ebSragge break;
737281464ebSragge }
738281464ebSragge if (rfc_sc->sc_bytesleft > i) {
739281464ebSragge rfc_sc->sc_bytesleft -= i;
740bf9a718bShe rfc_sc->sc_bufidx =
741bf9a718bShe (char *)rfc_sc->sc_bufidx + i;
742281464ebSragge } else {
743281464ebSragge biodone(rfc_sc->sc_curbuf);
744c049e276Sragge rf_sc = get_new_buf( rfc_sc);
745c049e276Sragge if (rf_sc == NULL)
746281464ebSragge return;
747281464ebSragge }
748281464ebSragge RFS_SETCMD(rf_sc->sc_state,
749281464ebSragge (rfc_sc->sc_curbuf->b_flags & B_READ) != 0
750281464ebSragge ? RFS_RSEC : RFS_FBUF);
751281464ebSragge break;
752281464ebSragge case RFS_FBUF: /* Fill Buffer */
753281464ebSragge disk_unbusy(&rf_sc->sc_disk, 0, 0);
754c049e276Sragge bus_dmamap_unload(rfc_sc->sc_dmat, rfc_sc->sc_dmam);
755281464ebSragge /* check for errors */
756c049e276Sragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
757c049e276Sragge RX2CS) & RX2CS_ERR) != 0) {
758281464ebSragge /* should do more verbose error reporting */
759281464ebSragge printf("rfc_intr: Error while DMA: %x\n",
760281464ebSragge bus_space_read_2(rfc_sc->sc_iot,
761281464ebSragge rfc_sc->sc_ioh, RX2ES));
76266fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
763281464ebSragge }
764281464ebSragge RFS_SETCMD(rf_sc->sc_state, RFS_WSEC);
765281464ebSragge break;
766281464ebSragge case RFS_EBUF: /* Empty Buffer */
767281464ebSragge i = (rf_sc->sc_state & RFS_DENS) == 0
768281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD;
769281464ebSragge disk_unbusy(&rf_sc->sc_disk, i, 1);
770c049e276Sragge bus_dmamap_unload(rfc_sc->sc_dmat, rfc_sc->sc_dmam);
771281464ebSragge /* check for errors */
772c049e276Sragge if ((bus_space_read_2(rfc_sc->sc_iot, rfc_sc->sc_ioh,
773c049e276Sragge RX2CS) & RX2CS_ERR) != 0) {
774281464ebSragge /* should do more verbose error reporting */
775281464ebSragge printf("rfc_intr: Error while DMA: %x\n",
776281464ebSragge bus_space_read_2(rfc_sc->sc_iot,
777281464ebSragge rfc_sc->sc_ioh, RX2ES));
77866fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
779c049e276Sragge break;
780281464ebSragge }
781281464ebSragge if (rfc_sc->sc_bytesleft > i) {
782281464ebSragge rfc_sc->sc_bytesleft -= i;
783bf9a718bShe rfc_sc->sc_bufidx =
784bf9a718bShe (char *)rfc_sc->sc_bufidx + i;
785281464ebSragge } else {
786281464ebSragge biodone(rfc_sc->sc_curbuf);
787c049e276Sragge rf_sc = get_new_buf( rfc_sc);
788c049e276Sragge if (rf_sc == NULL)
789281464ebSragge return;
790281464ebSragge }
791281464ebSragge RFS_SETCMD(rf_sc->sc_state,
792281464ebSragge (rfc_sc->sc_curbuf->b_flags & B_READ) != 0
793281464ebSragge ? RFS_RSEC : RFS_FBUF);
794281464ebSragge break;
795c049e276Sragge case RFS_NOTINIT: /* Device is not open */
796281464ebSragge case RFS_SMD: /* Set Media Density */
797281464ebSragge case RFS_RSTAT: /* Read Status */
798281464ebSragge case RFS_WDDS: /* Write Deleted Data Sector */
799281464ebSragge case RFS_REC: /* Read Error Code */
800281464ebSragge default:
8016827de95Sjkunz panic("Impossible state in rfc_intr(1): 0x%x\n",
8026827de95Sjkunz rf_sc->sc_state & RFS_CMDS);
803281464ebSragge }
804281464ebSragge
80566fefd11Sad if (rfc_sc->sc_curbuf->b_error != 0) {
806c049e276Sragge /*
807f05e6f1aSwiz * An error occurred while processing this buffer.
808c049e276Sragge * Finish it and try to get a new buffer to process.
809c049e276Sragge * Return if there are no buffers in the queues.
810c049e276Sragge * This loops until the queues are empty or a new
811c049e276Sragge * action was successfully scheduled.
812c049e276Sragge */
813c049e276Sragge rfc_sc->sc_curbuf->b_resid = rfc_sc->sc_bytesleft;
814281464ebSragge rfc_sc->sc_curbuf->b_error = EIO;
815281464ebSragge biodone(rfc_sc->sc_curbuf);
816c049e276Sragge rf_sc = get_new_buf( rfc_sc);
817c049e276Sragge if (rf_sc == NULL)
818281464ebSragge return;
819c049e276Sragge continue;
820281464ebSragge }
821281464ebSragge
822281464ebSragge /*
823281464ebSragge * ... then initiate next command.
824281464ebSragge */
825281464ebSragge switch (rf_sc->sc_state & RFS_CMDS) {
826281464ebSragge case RFS_EBUF: /* Empty Buffer */
827281464ebSragge i = bus_dmamap_load(rfc_sc->sc_dmat, rfc_sc->sc_dmam,
828281464ebSragge rfc_sc->sc_bufidx, (rf_sc->sc_state & RFS_DENS) == 0
829c049e276Sragge ? RX2_BYTE_SD : RX2_BYTE_DD,
830c049e276Sragge rfc_sc->sc_curbuf->b_proc, BUS_DMA_NOWAIT);
831281464ebSragge if (i != 0) {
832c049e276Sragge printf("rfc_intr: Error loading dmamap: %d\n",
833c049e276Sragge i);
83466fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
835281464ebSragge break;
836281464ebSragge }
837281464ebSragge disk_busy(&rf_sc->sc_disk);
838281464ebSragge if (rfc_sendcmd(rfc_sc, RX2CS_EBUF | RX2CS_IE
839281464ebSragge | ((rf_sc->sc_state & RFS_DENS) == 0 ? 0 : RX2CS_DD)
840281464ebSragge | (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
841c049e276Sragge | ((rfc_sc->sc_dmam->dm_segs[0].ds_addr
842c049e276Sragge & 0x30000) >>4), ((rf_sc->sc_state & RFS_DENS) == 0
843281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD) / 2,
844281464ebSragge rfc_sc->sc_dmam->dm_segs[0].ds_addr & 0xffff) < 0) {
845c049e276Sragge disk_unbusy(&rf_sc->sc_disk, 0, 1);
84666fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
847c049e276Sragge bus_dmamap_unload(rfc_sc->sc_dmat,
848c049e276Sragge rfc_sc->sc_dmam);
849281464ebSragge }
850281464ebSragge break;
851281464ebSragge case RFS_FBUF: /* Fill Buffer */
852281464ebSragge i = bus_dmamap_load(rfc_sc->sc_dmat, rfc_sc->sc_dmam,
853281464ebSragge rfc_sc->sc_bufidx, (rf_sc->sc_state & RFS_DENS) == 0
854281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD,
855281464ebSragge rfc_sc->sc_curbuf->b_proc, BUS_DMA_NOWAIT);
856281464ebSragge if (i != 0) {
857c049e276Sragge printf("rfc_intr: Error loading dmamap: %d\n",
858c049e276Sragge i);
85966fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
860281464ebSragge break;
861281464ebSragge }
862281464ebSragge disk_busy(&rf_sc->sc_disk);
863281464ebSragge if (rfc_sendcmd(rfc_sc, RX2CS_FBUF | RX2CS_IE
864281464ebSragge | ((rf_sc->sc_state & RFS_DENS) == 0 ? 0 : RX2CS_DD)
865281464ebSragge | (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
866c049e276Sragge | ((rfc_sc->sc_dmam->dm_segs[0].ds_addr
867c049e276Sragge & 0x30000)>>4), ((rf_sc->sc_state & RFS_DENS) == 0
868281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD) / 2,
869281464ebSragge rfc_sc->sc_dmam->dm_segs[0].ds_addr & 0xffff) < 0) {
870c049e276Sragge disk_unbusy(&rf_sc->sc_disk, 0, 0);
87166fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
872c049e276Sragge bus_dmamap_unload(rfc_sc->sc_dmat,
873c049e276Sragge rfc_sc->sc_dmam);
874281464ebSragge }
875281464ebSragge break;
876281464ebSragge case RFS_WSEC: /* Write Sector */
877281464ebSragge i = (rfc_sc->sc_curbuf->b_bcount - rfc_sc->sc_bytesleft
878281464ebSragge + rfc_sc->sc_curbuf->b_blkno * DEV_BSIZE) /
879281464ebSragge ((rf_sc->sc_state & RFS_DENS) == 0
880281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD);
881281464ebSragge if (i > RX2_TRACKS * RX2_SECTORS) {
88266fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
883c049e276Sragge break;
884281464ebSragge }
885281464ebSragge disk_busy(&rf_sc->sc_disk);
886281464ebSragge if (rfc_sendcmd(rfc_sc, RX2CS_WSEC | RX2CS_IE
887281464ebSragge | (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
888281464ebSragge | ((rf_sc->sc_state& RFS_DENS) == 0 ? 0 : RX2CS_DD),
889281464ebSragge i % RX2_SECTORS + 1, i / RX2_SECTORS) < 0) {
890c049e276Sragge disk_unbusy(&rf_sc->sc_disk, 0, 0);
89166fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
892281464ebSragge }
893281464ebSragge break;
894281464ebSragge case RFS_RSEC: /* Read Sector */
895281464ebSragge i = (rfc_sc->sc_curbuf->b_bcount - rfc_sc->sc_bytesleft
896281464ebSragge + rfc_sc->sc_curbuf->b_blkno * DEV_BSIZE) /
897281464ebSragge ((rf_sc->sc_state & RFS_DENS) == 0
898281464ebSragge ? RX2_BYTE_SD : RX2_BYTE_DD);
899281464ebSragge if (i > RX2_TRACKS * RX2_SECTORS) {
90066fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
901c049e276Sragge break;
902281464ebSragge }
903281464ebSragge disk_busy(&rf_sc->sc_disk);
904281464ebSragge if (rfc_sendcmd(rfc_sc, RX2CS_RSEC | RX2CS_IE
905281464ebSragge | (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
906281464ebSragge | ((rf_sc->sc_state& RFS_DENS) == 0 ? 0 : RX2CS_DD),
907281464ebSragge i % RX2_SECTORS + 1, i / RX2_SECTORS) < 0) {
908c049e276Sragge disk_unbusy(&rf_sc->sc_disk, 0, 1);
90966fefd11Sad rfc_sc->sc_curbuf->b_error = EIO;
910281464ebSragge }
911281464ebSragge break;
912c049e276Sragge case RFS_NOTINIT: /* Device is not open */
913c049e276Sragge case RFS_PROBING: /* density detect / verify started */
914c049e276Sragge case RFS_IDLE: /* controller is idle */
915281464ebSragge case RFS_SMD: /* Set Media Density */
916281464ebSragge case RFS_RSTAT: /* Read Status */
917281464ebSragge case RFS_WDDS: /* Write Deleted Data Sector */
918281464ebSragge case RFS_REC: /* Read Error Code */
919281464ebSragge default:
9206827de95Sjkunz panic("Impossible state in rfc_intr(2): 0x%x\n",
9216827de95Sjkunz rf_sc->sc_state & RFS_CMDS);
922281464ebSragge }
923281464ebSragge
92466fefd11Sad if (rfc_sc->sc_curbuf->b_error != 0) {
925c049e276Sragge /*
926f05e6f1aSwiz * An error occurred while processing this buffer.
927c049e276Sragge * Finish it and try to get a new buffer to process.
928c049e276Sragge * Return if there are no buffers in the queues.
929c049e276Sragge * This loops until the queues are empty or a new
930c049e276Sragge * action was successfully scheduled.
931c049e276Sragge */
932c049e276Sragge rfc_sc->sc_curbuf->b_resid = rfc_sc->sc_bytesleft;
933281464ebSragge rfc_sc->sc_curbuf->b_error = EIO;
934281464ebSragge biodone(rfc_sc->sc_curbuf);
935c049e276Sragge rf_sc = get_new_buf( rfc_sc);
936c049e276Sragge if (rf_sc == NULL)
937c049e276Sragge return;
938c049e276Sragge continue;
939281464ebSragge }
940bc2387e2Sdsl break;
941bc2387e2Sdsl }
942281464ebSragge return;
943281464ebSragge }
944281464ebSragge
945281464ebSragge
946281464ebSragge
947281464ebSragge int
rfdump(dev_t dev,daddr_t blkno,void * va,size_t size)94853524e44Schristos rfdump(dev_t dev, daddr_t blkno, void *va, size_t size)
949281464ebSragge {
950281464ebSragge
951281464ebSragge /* A 0.5MB floppy is much to small to take a system dump... */
952281464ebSragge return(ENXIO);
953281464ebSragge }
954281464ebSragge
955281464ebSragge
956281464ebSragge
957281464ebSragge int
rfsize(dev_t dev)958281464ebSragge rfsize(dev_t dev)
959281464ebSragge {
960281464ebSragge
961281464ebSragge return(-1);
962281464ebSragge }
963281464ebSragge
964281464ebSragge
965281464ebSragge
966281464ebSragge int
rfopen(dev_t dev,int oflags,int devtype,struct lwp * l)96795e1ffb1Schristos rfopen(dev_t dev, int oflags, int devtype, struct lwp *l)
968281464ebSragge {
969281464ebSragge struct rf_softc *rf_sc;
970281464ebSragge struct rfc_softc *rfc_sc;
971281464ebSragge struct disklabel *dl;
972281464ebSragge
973dfba8166Smatt if ((rf_sc = device_lookup_private(&rf_cd, DISKUNIT(dev))) == NULL)
974dfba8166Smatt return ENXIO;
975dfba8166Smatt
976dfba8166Smatt rfc_sc = rf_sc->sc_rfc;
977281464ebSragge dl = rf_sc->sc_disk.dk_label;
978281464ebSragge switch (DISKPART(dev)) {
979281464ebSragge case 0: /* Part. a is single density. */
9809876532dSwiz /* opening in single and double density is senseless */
981c049e276Sragge if ((rf_sc->sc_state & RFS_OPEN_B) != 0 )
982c049e276Sragge return(ENXIO);
983281464ebSragge rf_sc->sc_state &= ~RFS_DENS;
984281464ebSragge rf_sc->sc_state &= ~RFS_AD;
985c049e276Sragge rf_sc->sc_state |= RFS_OPEN_A;
986281464ebSragge break;
987281464ebSragge case 1: /* Part. b is double density. */
988281464ebSragge /*
9899876532dSwiz * Opening a single density only drive in double
990c049e276Sragge * density or simultaneous opening in single and
9919876532dSwiz * double density is senseless.
992281464ebSragge */
993c049e276Sragge if (rfc_sc->type == 1
994c049e276Sragge || (rf_sc->sc_state & RFS_OPEN_A) != 0 )
995281464ebSragge return(ENXIO);
996281464ebSragge rf_sc->sc_state |= RFS_DENS;
997281464ebSragge rf_sc->sc_state &= ~RFS_AD;
998c049e276Sragge rf_sc->sc_state |= RFS_OPEN_B;
999281464ebSragge break;
1000281464ebSragge case 2: /* Part. c is auto density. */
1001281464ebSragge rf_sc->sc_state |= RFS_AD;
1002c049e276Sragge rf_sc->sc_state |= RFS_OPEN_C;
1003281464ebSragge break;
1004281464ebSragge default:
1005281464ebSragge return(ENXIO);
1006281464ebSragge break;
1007281464ebSragge }
1008281464ebSragge if ((rf_sc->sc_state & RFS_CMDS) == RFS_NOTINIT) {
1009281464ebSragge rfc_sc->sc_curchild = rf_sc->sc_dnum;
1010281464ebSragge /*
1011281464ebSragge * Controller is idle and density is not detected.
1012281464ebSragge * Start a density probe by issuing a read sector command
1013281464ebSragge * and sleep until the density probe finished.
1014*38ad5e0eSandvar * Due to this it is impossible to open unformatted media.
1015281464ebSragge * As the RX02/02 is not able to format its own media,
1016*38ad5e0eSandvar * media must be purchased preformatted. fsck DEC marketing!
1017281464ebSragge */
1018281464ebSragge RFS_SETCMD(rf_sc->sc_state, RFS_PROBING);
1019281464ebSragge disk_busy(&rf_sc->sc_disk);
1020281464ebSragge if (rfc_sendcmd(rfc_sc, RX2CS_RSEC | RX2CS_IE
1021281464ebSragge | (rf_sc->sc_dnum == 0 ? 0 : RX2CS_US)
1022281464ebSragge | ((rf_sc->sc_state & RFS_DENS) == 0 ? 0 : RX2CS_DD),
1023281464ebSragge 1, 1) < 0) {
1024281464ebSragge rf_sc->sc_state = 0;
1025281464ebSragge return(ENXIO);
1026281464ebSragge }
1027281464ebSragge /* wait max. 2 sec for density probe to finish */
1028281464ebSragge if (tsleep(rf_sc, PRIBIO | PCATCH, "density probe", 2 * hz)
1029281464ebSragge != 0 || (rf_sc->sc_state & RFS_CMDS) == RFS_NOTINIT) {
10309876532dSwiz /* timeout elapsed and / or something went wrong */
1031281464ebSragge rf_sc->sc_state = 0;
1032281464ebSragge return(ENXIO);
1033281464ebSragge }
1034281464ebSragge }
1035281464ebSragge /* disklabel. We use different fake geometries for SD and DD. */
1036281464ebSragge if ((rf_sc->sc_state & RFS_DENS) == 0) {
1037281464ebSragge dl->d_nsectors = 10; /* sectors per track */
1038281464ebSragge dl->d_secpercyl = 10; /* sectors per cylinder */
1039281464ebSragge dl->d_ncylinders = 50; /* cylinders per unit */
1040281464ebSragge dl->d_secperunit = 501; /* sectors per unit */
1041281464ebSragge /* number of sectors in partition */
1042281464ebSragge dl->d_partitions[2].p_size = 500;
1043281464ebSragge } else {
1044281464ebSragge dl->d_nsectors = RX2_SECTORS / 2; /* sectors per track */
1045281464ebSragge dl->d_secpercyl = RX2_SECTORS / 2; /* sectors per cylinder */
1046281464ebSragge dl->d_ncylinders = RX2_TRACKS; /* cylinders per unit */
1047281464ebSragge /* sectors per unit */
1048281464ebSragge dl->d_secperunit = RX2_SECTORS * RX2_TRACKS / 2;
1049281464ebSragge /* number of sectors in partition */
1050281464ebSragge dl->d_partitions[2].p_size = RX2_SECTORS * RX2_TRACKS / 2;
1051281464ebSragge }
1052281464ebSragge return(0);
1053281464ebSragge }
1054281464ebSragge
1055281464ebSragge
1056281464ebSragge
1057281464ebSragge int
rfclose(dev_t dev,int fflag,int devtype,struct lwp * l)105895e1ffb1Schristos rfclose(dev_t dev, int fflag, int devtype, struct lwp *l)
1059281464ebSragge {
10606827de95Sjkunz struct rf_softc *rf_sc = device_lookup_private(&rf_cd, DISKUNIT(dev));
1061281464ebSragge
1062c049e276Sragge if ((rf_sc->sc_state & 1 << (DISKPART(dev) + RFS_OPEN_SHIFT)) == 0)
10639876532dSwiz panic("rfclose: can not close non-open drive %s "
106423efc364Scegger "partition %"PRIu32, device_xname(rf_sc->sc_dev), DISKPART(dev));
1065c049e276Sragge else
1066c049e276Sragge rf_sc->sc_state &= ~(1 << (DISKPART(dev) + RFS_OPEN_SHIFT));
1067c049e276Sragge if ((rf_sc->sc_state & RFS_OPEN_MASK) == 0)
1068281464ebSragge rf_sc->sc_state = 0;
1069281464ebSragge return(0);
1070281464ebSragge }
1071281464ebSragge
1072281464ebSragge
1073281464ebSragge
1074281464ebSragge int
rfread(dev_t dev,struct uio * uio,int ioflag)1075281464ebSragge rfread(dev_t dev, struct uio *uio, int ioflag)
1076281464ebSragge {
1077281464ebSragge
1078281464ebSragge return(physio(rfstrategy, NULL, dev, B_READ, minphys, uio));
1079281464ebSragge }
1080281464ebSragge
1081281464ebSragge
1082281464ebSragge
1083281464ebSragge int
rfwrite(dev_t dev,struct uio * uio,int ioflag)1084281464ebSragge rfwrite(dev_t dev, struct uio *uio, int ioflag)
1085281464ebSragge {
1086281464ebSragge
1087281464ebSragge return(physio(rfstrategy, NULL, dev, B_WRITE, minphys, uio));
1088281464ebSragge }
1089281464ebSragge
1090281464ebSragge
1091281464ebSragge
1092281464ebSragge int
rfioctl(dev_t dev,u_long cmd,void * data,int fflag,struct lwp * l)109353524e44Schristos rfioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l)
1094281464ebSragge {
10956827de95Sjkunz struct rf_softc *rf_sc = device_lookup_private(&rf_cd, DISKUNIT(dev));
1096c60db2e9Schristos int error;
1097281464ebSragge
10989876532dSwiz /* We are going to operate on a non-open dev? PANIC! */
1099c049e276Sragge if ((rf_sc->sc_state & 1 << (DISKPART(dev) + RFS_OPEN_SHIFT)) == 0)
1100c049e276Sragge panic("rfioctl: can not operate on non-open drive %s "
110123efc364Scegger "partition %"PRIu32, device_xname(rf_sc->sc_dev), DISKPART(dev));
1102c60db2e9Schristos error = disk_ioctl(&rf_sc->sc_disk, dev, cmd, data, fflag, l);
1103c60db2e9Schristos if (error != EPASSTHROUGH)
1104c60db2e9Schristos return error;
1105c60db2e9Schristos
1106281464ebSragge switch (cmd) {
11078d10f962Schristos /* get and set disklabel; DIOCGPARTINFO used internally */
1108281464ebSragge case DIOCSDINFO: /* set */
1109281464ebSragge return(0);
1110281464ebSragge case DIOCWDINFO: /* set, update disk */
1111281464ebSragge return(0);
1112281464ebSragge /* do format operation, read or write */
1113281464ebSragge case DIOCRFORMAT:
1114281464ebSragge break;
1115281464ebSragge case DIOCWFORMAT:
1116281464ebSragge break;
1117281464ebSragge
1118281464ebSragge case DIOCSSTEP: /* set step rate */
1119281464ebSragge break;
1120281464ebSragge case DIOCSRETRIES: /* set # of retries */
1121281464ebSragge break;
1122281464ebSragge case DIOCKLABEL: /* keep/drop label on close? */
1123281464ebSragge break;
1124281464ebSragge case DIOCWLABEL: /* write en/disable label */
1125281464ebSragge break;
1126281464ebSragge
1127281464ebSragge /* case DIOCSBAD: / * set kernel dkbad */
1128281464ebSragge break; /* */
1129281464ebSragge case DIOCEJECT: /* eject removable disk */
1130281464ebSragge break;
1131281464ebSragge case ODIOCEJECT: /* eject removable disk */
1132281464ebSragge break;
1133281464ebSragge case DIOCLOCK: /* lock/unlock pack */
1134281464ebSragge break;
1135281464ebSragge
1136281464ebSragge /* get default label, clear label */
1137281464ebSragge case DIOCGDEFLABEL:
1138281464ebSragge break;
1139281464ebSragge case DIOCCLRLABEL:
1140281464ebSragge break;
1141281464ebSragge default:
1142281464ebSragge return(ENOTTY);
1143281464ebSragge }
1144281464ebSragge
1145281464ebSragge return(ENOTTY);
1146281464ebSragge }
1147