xref: /netbsd-src/sys/arch/emips/stand/common/ace.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: ace.c,v 1.2 2011/07/17 20:54:39 joerg Exp $	*/
2 
3 /*-
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code was written by Alessandro Forin and Neil Pittman
9  * at Microsoft Research and contributed to The NetBSD Foundation
10  * by Microsoft Corporation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /* --------------------------------------------------------------------------
35  *
36  * Module:
37  *
38  *    ace.c
39  *
40  * Purpose:
41  *
42  *    Driver for the Xilinx System ACE CompactFlash Solution
43  *
44  * Author:
45  *    A. Forin (sandrof)
46  *
47  * References:
48  *    "System ACE CompactFlash Solution", Advance Product Specification
49  *    Document DS080 Version 1.5 April 5, 2002.  Xilinx Corp.
50  *    Available at http://www.xilinx.com
51  *
52  *    "CF+ and CompactFlash Specification", Revision 4.1, 02/16/2007.
53  *    CompactFlash Association.
54  *    Available at http://www.compactflash.org
55  * --------------------------------------------------------------------------
56  */
57 
58 #include <lib/libsa/stand.h>
59 #include <lib/libkern/libkern.h>
60 #include <machine/emipsreg.h>
61 
62 #include <sys/param.h>
63 #include <sys/disklabel.h>
64 #include <sys/endian.h>
65 
66 #include "common.h"
67 #include "ace.h"
68 
69 #define NSAC 2
70 #define SAC0 ((struct _Sac  *)IDE_DEFAULT_ADDRESS)
71 #define SAC1 ((struct _Sac  *)(IDE_DEFAULT_ADDRESS+256))
72 
73 #define CF_SECBITS     9
74 #define CF_SECTOR_SIZE (1 << CF_SECBITS)
75 
76 
77 /* Error codes
78  */
79 #define FAILED(x)           (x < 0)
80 #define S_OK                (0)
81 #define E_INVALID_PARAMETER (-1)
82 #define E_DISK_RESET_FAILED (-2)
83 #define E_NO_MEDIA_IN_DRIVE (-3)
84 #define E_TIMED_OUT         (-4)
85 
86 /* Utilities
87  */
88 #if defined(DEBUG)
89 int acedebug = 2;
90 #define DBGME(lev,x) if (lev >= acedebug) x
91 #else
92 #define DBGME(lev,x)
93 #endif
94 
95 #if defined(DEBUG)
96 typedef char *NAME;
97 typedef struct _REGDESC {
98     NAME RegisterName;
99     NAME BitNames[32];
100 } REGDESC, *PREGDESC;
101 
102 static void SysacePrintRegister(const REGDESC *Desc, uint32_t Value);
103 
104 static void SysacePrintRegister(const REGDESC *Desc, uint32_t Value)
105 {
106     int i;
107     printf("\t%s %x =", Desc->RegisterName, Value);
108     for (i = 31; i >= 0; i--) {
109         if (Value & (1 << i))
110             printf(" %s",
111                      (Desc->BitNames[i]) ? Desc->BitNames[i] : "?");
112     }
113     printf("\n");
114 }
115 
116 static void SysaceDumpRegisters(struct _Sac *Interface)
117 {
118 	const REGDESC Control_Names =
119         { "Control",
120           {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
121           "RST", //			0x00010000
122           "BUS8", //		0x00020000
123           "BUS16", //		0x00040000
124           "BUS32", //		0x00080000
125           "IRQ", //			0x00100000
126           "BRDY", //		0x00200000
127           "IMSK0", //		0x00400000
128           "IMSK1", //		0x00800000
129           "TD0", //	    	0x0f000000
130           "TD1", //		    0x0f000000
131           "TD2", //	    	0x0f000000
132           "TD3", //	    	0x0f000000
133           "BUFW8", //		0x10000000
134           "BUFW16", //		0x20000000
135           "BUFW32", //		0x40000000
136           "DEBUG"} //		0x80000000
137         };
138 
139 	const REGDESC STATUS_Names =
140         { "STATUS",
141           {"CFGLOCK", //	0x00000001
142           "MPULOCK", //		0x00000002
143           "CFGERROR", //	0x00000004
144           "CFCERROR", //	0x00000008
145           "CFDETECT", //	0x00000010
146           "DATABUFRDY", //	0x00000020
147           "DATABUFWRITE", //0x00000040
148           "CFGDONE", //		0x00000080
149           "RDYFORCFCMD", //	0x00000100
150           "CFGMODEPIN", //	0x00000200
151           0,0,0,
152           "CFGADDRPIN0", //	0x0000e000
153           "CFGADDRPIN1", //	0x0000e000
154           "CFGADDRPIN2", //	0x0000e000
155           0,
156           "CFBSY", //		0x00020000
157           "CFRDY", //		0x00040000
158           "CFDWF", //		0x00080000
159           "CFDSC", //		0x00100000
160           "CFDRQ", //		0x00200000
161           "CFCORR", //		0x00400000
162           "CFERR", //		0x00800000
163           0,}
164         };
165 
166 	const REGDESC ERRORREG_Names =
167         { "ERRORREG",
168           {"CARDRESETERR", //			0x00000001
169           "CARDRDYERR", //				0x00000002
170           "CARDREADERR", //				0x00000004
171           "CARDWRITEERR", //			0x00000008
172           "SECTORRDYERR", //			0x00000010
173           "CFGADDRERR", //				0x00000020
174           "CFGFAILED", //				0x00000040
175           "CFGREADERR", //				0x00000080
176           "CFGINSTRERR", //				0x00000100
177           "CFGINITERR", //				0x00000200
178           0,
179           "CFBBK", //					0x00000800
180           "CFUNC", //					0x00001000
181           "CFIDNF", //					0x00002000
182           "CFABORT", //					0x00004000
183           "CFAMNF", //					0x00008000
184            0,}
185         };
186 
187     const NAME CommandNames[8] =
188         { "0", //     				0x0000
189           "RESETMEMCARD", //   		0x0100
190           "IDENTIFYMEMCARD", //		0x0200
191           "READMEMCARDDATA", //		0x0300
192           "WRITEMEMCARDDATA", //  	0x0400
193           "5", //     				0x0500
194           "ABORT", //			    0x0600
195           "7" //     			    0x0700
196         };
197 
198 	const REGDESC CONTROLREG_Names =
199         { "CONTROLREG",
200           {"FORCELOCKREQ", //			0x00000001
201           "LOCKREQ", //					0x00000002
202           "FORCECFGADDR", //			0x00000004
203           "FORCECFGMODE", //			0x00000008
204           "CFGMODE", //					0x00000010
205           "CFGSTART", //				0x00000020
206           "CFGSEL_MPU", //  			0x00000040
207           "CFGRESET", //				0x00000080
208           "DATABUFRDYIRQ", //			0x00000100
209           "ERRORIRQ", //				0x00000200
210           "CFGDONEIRQ", //				0x00000400
211           "RESETIRQ", //				0x00000800
212           "CFGPROG", //					0x00001000
213           "CFGADDR_B0", //				0x00002000
214           "CFGADDR_B1", //				0x00004000
215           "CFGADDR_B2", //				0x00008000
216           0,}
217         };
218 
219 	const REGDESC FATSTATREG_Names =
220         { "FATSTATREG",
221           {"MBRVALID", //				0x00000001
222           "PBRVALID", //				0x00000002
223           "MBRFAT12", //				0x00000004
224           "PBRFAT12", //				0x00000008
225           "MBRFAT16", //				0x00000010
226           "PBRFAT16", //				0x00000020
227           "CALCFAT12", //				0x00000040
228           "CALCFAT16", //				0x00000080
229           0, }
230         };
231 
232     printf("Sysace@%p:\n", Interface);
233     printf("\tTag %x\n", Interface->Tag);
234     SysacePrintRegister(&Control_Names, Interface->Control);
235     printf("\tBUSMODEREG %x\n", Interface->BUSMODEREG);
236     SysacePrintRegister(&STATUS_Names, Interface->STATUS);
237     SysacePrintRegister(&ERRORREG_Names, Interface->ERRORREG);
238     printf("\tCFGLBAREG %x\n", Interface->CFGLBAREG);
239     printf("\tMPULBAREG %x\n", Interface->MPULBAREG);
240     printf("\tVERSIONREG %x\n", Interface->VERSIONREG);
241     printf("\tSECCNTCMDREG %x = %s cnt=%d\n", Interface->SECCNTCMDREG,
242              CommandNames[(Interface->SECCNTCMDREG >> 8)&7],
243              Interface->SECCNTCMDREG & SAC_SECCCNT);
244     SysacePrintRegister(&CONTROLREG_Names, Interface->CONTROLREG);
245     SysacePrintRegister(&FATSTATREG_Names, Interface->FATSTATREG);
246 }
247 
248 #else
249 #define SysaceDumpRegisters(_c_)
250 #endif
251 
252 /* Reset the device and the interface
253  */
254 static int SysaceInitialize(struct _Sac *Interface)
255 {
256     /* 16bit mode etc etc */
257 	uint32_t BusMode, Control;
258 
259     /* reset our interface */
260     Interface->Control = SAC_RST;
261     Delay(200);
262 
263     /* repeat on both byte lanes */
264 	Interface->BUSMODEREG = SAC_MODE16 | (SAC_MODE16 << 8);
265     Delay(1);
266 
267     /* check what our interface does and what the SysACE expects */
268 	Control = Interface->Control;
269 	BusMode = Interface->BUSMODEREG;
270 
271     /* get them to agree */
272 	if (BusMode & SAC_MODE16)
273 	{
274 		Interface->Control = Control | SAC_BUS16;
275 		Interface->Control = Interface->Control & ~SAC_BUS8;
276 	}
277 	else
278 	{
279 		Interface->Control = Control | SAC_BUS8;
280 		Interface->Control = Interface->Control & ~SAC_BUS16;
281 	}
282 
283     /* check that it worked */
284 	BusMode = Interface->BUSMODEREG;
285 	Control = Interface->Control;
286 
287 	if (((BusMode & SAC_MODE16) == 0) && ((Control & SAC_BUS8) == 0)) return E_DISK_RESET_FAILED;
288 	if (((BusMode & SAC_MODE16) > 0) && ((Control & SAC_BUS16) == 0)) return E_DISK_RESET_FAILED;
289 
290     /* interrupts off for now */
291     Interface->Control &= ~SAC_INTMASK;
292 #define SAC_INTERRUPTS (SAC_DATABUFRDYIRQ |	SAC_ERRORIRQ )// | SAC_CFGDONEIRQ)
293     Control = Interface->CONTROLREG;
294     Control = (Control & ~SAC_INTERRUPTS) | SAC_RESETIRQ | SAC_FORCECFGMODE;
295     Interface->CONTROLREG = Control;
296     Interface->CONTROLREG = Control & ~SAC_RESETIRQ;
297 
298     /* no command */
299     Interface->MPULBAREG = 0;
300 
301     return S_OK;
302 }
303 
304 /* Take control of the ACE datapath
305  */
306 static int SysaceLock(struct _Sac *Interface)
307 {
308     uint32_t Status;
309     int i;
310 
311     /* Locked already?
312      */
313     Status = Interface->STATUS;
314     if (Status & SAC_MPULOCK)
315         return TRUE;
316 
317     /* Request lock
318      */
319     Interface->CONTROLREG |= SAC_LOCKREQ;
320 
321     /* Spin a bit until we get it
322      */
323     for (i = 0; i < 200; i++) {
324         Status = Interface->STATUS;
325         if (Status & SAC_MPULOCK)
326             return TRUE;
327         Delay(100);
328         DBGME(0,printf("Sysace::Lock loops.. (st=%x)\n",Status));
329     }
330 
331     /* oopsie!
332      */
333     DBGME(3,printf("Sysace::Lock timeout (st=%x)\n",Status));
334     SysaceDumpRegisters(Interface);
335     return FALSE;
336 }
337 
338 /* Release control of the ACE datapath
339  */
340 static int SysaceUnlock(struct _Sac *Interface)
341 {
342     uint32_t Status;
343     int i;
344 
345     /* Clear reset
346      */
347     Interface->CONTROLREG &= ~SAC_CFGRESET;
348 
349     /* Unlocked already?
350      */
351     Status = Interface->STATUS;
352     if (0 == (Status & SAC_MPULOCK))
353         return TRUE;
354 
355     /* Request unlock
356      */
357     Interface->CONTROLREG &= ~SAC_LOCKREQ;
358 
359     /* Spin a bit until we get it
360      */
361     for (i = 0; i < 200; i++) {
362         Status = Interface->STATUS;
363         if (0 == (Status & SAC_MPULOCK))
364             return TRUE;
365         Delay(100);
366         DBGME(0,printf("Sysace::Unlock loops.. (st=%x)\n",Status));
367     }
368 
369     /* oopsie!
370      */
371     DBGME(3,printf("Sysace::Unlock timeout (st=%x)\n",Status));
372     SysaceDumpRegisters(Interface);
373     return FALSE;
374 }
375 
376 /* Check if the ACE is waiting for a comamnd
377  */
378 #define SysaceReadyForCommand(_i_) ((_i_)->STATUS & SAC_RDYFORCFCMD)
379 
380 /* Check if the ACE is executing a comamnd
381  */
382 #define SysaceBusyWithCommand(_i_) ((_i_)->STATUS & SAC_CFBSY)
383 
384 /* Turn on interrupts from the ACE
385  */
386 #define SysaceInton(_i_) { \
387           (_i_)->CONTROLREG |= SAC_INTERRUPTS; \
388           (_i_)->Control |= SAC_INTMASK; \
389 }
390 
391 /* Turn off interrupts from the ACE
392  */
393 #define SysaceIntoff(_i_) { \
394           (_i_)->CONTROLREG &= ~SAC_INTERRUPTS; \
395           (_i_)->Control &= ~SAC_INTMASK; \
396 }
397 
398 /* Start a command on the ACE, such as read or identify.
399  */
400 static int SysaceStartCommand(struct _Sac *Interface,
401                               uint32_t Command,
402                               uint32_t Lba,
403                               uint32_t nSectors)
404 {
405     int sc = E_DISK_RESET_FAILED;
406 
407     /* Lock it if not already
408      */
409     if (!SysaceLock(Interface)) {
410         /* printed already */
411         return sc;
412     }
413 
414     /* Is there a CF inserted
415      */
416     if (! (Interface->STATUS & SAC_CFDETECT)) {
417         /* NB: Not a failure state */
418         DBGME(2,printf("Sysace:: no media (st=%x)\n",Interface->STATUS));
419         return E_NO_MEDIA_IN_DRIVE;
420     }
421 
422     /* Is it ready for a command
423      */
424     if (!SysaceReadyForCommand(Interface)) {
425         DBGME(3,printf("Sysace:: not ready (st=%x)\n",Interface->STATUS));
426         SysaceDumpRegisters(Interface);
427         return sc;
428     }
429 
430     /* sector number and command
431      */
432     Interface->MPULBAREG = Lba;
433     Interface->SECCNTCMDREG = (uint16_t)(Command | (nSectors & SAC_SECCCNT));
434 
435     /* re-route the chip
436      * NB: The word "RESET" is actually not much of a misnomer.
437      * The chip was designed for a one-shot execution only, at reset time,
438      * namely loading the configuration data into the FPGA. So..
439      */
440     Interface->CONTROLREG |= SAC_CFGRESET;
441     return S_OK;
442 }
443 
444 
445 /* "Interrupt service routine"
446  */
447 static void SysAce_isr ( struct _Sac *Interface )
448 {
449     uint32_t Control;
450 
451     /* Turn off interrupts and ACK them
452      */
453     SysaceIntoff(Interface);
454 
455     Control = Interface->CONTROLREG & (~(SAC_RESETIRQ|SAC_INTERRUPTS));
456     Interface->CONTROLREG = Control | SAC_RESETIRQ;
457     Interface->CONTROLREG = Control;
458 }
459 
460 static int SysAce_wait(struct _Sac *Interface)
461 {
462     int i;
463     for (i = 0; i < 30000; i++) {
464         if (Interface->STATUS & SAC_DATABUFRDY) {
465             SysAce_isr(Interface);
466             return S_OK;
467         }
468         Delay(100);
469     }
470     return E_TIMED_OUT;
471 }
472 
473 
474 /* Read NBLOCKS blocks of 512 bytes each,
475  * starting at block number STARTSECTOR,
476  * into the buffer BUFFER.
477  * Return 0 if ok, -1 otherwise.
478  */
479 static int SysAce_read(struct _Sac * Interface, char *Buffer, uint32_t StartSector, uint32_t nBlocks)
480 {
481     int sc = S_OK;
482     uint32_t Size, SizeThisTime;
483     uint32_t Status = 0, SizeRead = 0;
484     unsigned int i, j;
485 
486     Size = nBlocks << CF_SECBITS;
487 
488     DBGME(1,printf("Sysace Read(%p %x %x)\n",
489                      Buffer, StartSector, nBlocks));
490 
491     /* Repeat until we are done or error
492      */
493     while (sc == S_OK) {
494 
495         /* .. one sector at a time
496          * BUGBUG Supposedly we can do up to 256 sectors?
497          */
498         SizeThisTime = Size;
499         if (SizeThisTime > CF_SECTOR_SIZE)
500             SizeThisTime = CF_SECTOR_SIZE;
501 
502         /*  Start a new sector read
503          */
504         SysaceInton(Interface);
505         sc = SysaceStartCommand(Interface,
506                                 SAC_CMD_READMEMCARDDATA,
507                                 StartSector,
508                                 1);
509         /* And wait until done, if ok
510          */
511         if (!FAILED(sc)) {
512             sc = SysAce_wait(Interface);
513         }
514 
515         /* Are we doing ok
516          */
517         if (!FAILED(sc)) {
518 
519             /* Get the data out of the ACE
520              */
521             for (i = 0; i < SizeThisTime; i += 4) {
522 
523                 /* Make sure the FIFO is ready
524                  */
525                 for (j = 0; j < 100; j++) {
526                     Status = Interface->STATUS;
527                     if (Status & SAC_DATABUFRDY)
528                         break;
529                     Delay(10);
530                 }
531 
532                 /* Got it?
533                  */
534                 if (Status & SAC_DATABUFRDY) {
535                     uint32_t Data32;
536 
537                     Data32 = Interface->DATABUFREG[0];
538                     Data32 = le32toh(Data32);
539 DBGME(0,printf(" %x", Data32));
540 if (0 == (0xf & (i+4) )) DBGME(0,printf("\n"));
541                     memcpy(Buffer+i,&Data32,4);
542                 }
543                 else
544                 {
545                     /* Ooops, get out of here
546                      */
547                     DBGME(3,printf("Sysace::READ timeout\n"));
548                     SysaceDumpRegisters(Interface);
549                     sc = E_TIMED_OUT;
550                     break;
551                 }
552             }
553 
554             /* Still doing ok?
555              */
556             if (!FAILED(sc)) {
557                 StartSector        += 1;
558                 Buffer             += SizeThisTime;
559                 SizeRead           += SizeThisTime;
560                 Size               -= SizeThisTime;
561             }
562         }
563 
564         /* Free the ACE for the JTAG, just in case */
565         SysaceUnlock(Interface);
566 
567         /* Are we done yet?
568          */
569         if (Size == 0)
570             break;
571     }
572 
573     return sc;
574 }
575 
576 /* Exported interface
577  */
578 struct	ace_softc {
579     struct _Sac *sc_dp;         /* I/O regs */
580 	int	sc_part;		        /* disk partition number */
581 	struct	disklabel sc_label;	/* disk label for this disk */
582 };
583 
584 #define	RF_PROTECTED_SECTORS	64	/* XXX refer to <.../rf_optnames.h> */
585 
586 int aceprobe(int unit)
587 {
588     struct _Sac *Sac;
589 
590     if (unit == 0)
591         Sac = SAC0;
592     else if (unit == 1)
593         Sac = SAC1;
594     else
595         return E_INVALID_PARAMETER;
596 
597     /* Check the tag to see if its there
598      */
599     if ((Sac->Tag & SAC_TAG) != PMTTAG_SYSTEM_ACE) {
600         DBGME(3,printf("init_ace: bad tag (%x != %x) @x%p\n",
601                        Sac->Tag, PMTTAG_SYSTEM_ACE, Sac));
602         return E_INVALID_PARAMETER;
603     }
604 
605     return S_OK;
606 }
607 
608 /* aceopen("", ctlr, unit, part);
609  */
610 int
611 aceopen(struct open_file *f, ...)
612 {
613 	int ctlr, unit, part;
614     struct _Sac *Sac;
615 
616 	struct ace_softc *sc;
617 	struct disklabel *lp;
618 	int i;
619 	char *msg;
620 	char buf[DEV_BSIZE];
621 	int cnt;
622 	va_list ap;
623 
624 	va_start(ap, f);
625 
626 	ctlr = va_arg(ap, int);
627 	unit = va_arg(ap, int);
628 	part = va_arg(ap, int);
629 	va_end(ap);
630 
631 	if (ctlr != 0 || unit >= NSAC || part >= 8)
632 		return (ENXIO);
633 
634     /* Is it there, does it work.
635      */
636     Sac = (unit == 0) ? SAC0 : SAC1;
637     i = aceprobe(unit);
638 	if (i < 0)
639         goto Bad;
640 
641     if (SysaceInitialize(Sac) < 0) {
642         DBGME(3,printf("ace%d: no reset @x%p\n", unit, Sac));
643     Bad:
644 		printf("open failed\n");
645 		return (ENXIO);
646     }
647 
648     /* Yep, go ahead.
649      */
650 	sc = alloc(sizeof(struct ace_softc));
651 	memset(sc, 0, sizeof(struct ace_softc));
652 	f->f_devdata = (void *)sc;
653 
654 	sc->sc_dp = Sac;
655 	sc->sc_part = part;
656 
657 	/* try to read disk label and partition table information */
658 	lp = &sc->sc_label;
659 	lp->d_secsize = DEV_BSIZE;
660 	lp->d_secpercyl = 1;
661 	lp->d_npartitions = MAXPARTITIONS;
662 	lp->d_partitions[part].p_offset = 0;
663 	lp->d_partitions[part].p_size = 0x7fffffff;
664 
665 	i = acestrategy(sc, F_READ, (daddr_t)LABELSECTOR, DEV_BSIZE, buf, &cnt);
666 	if (i || cnt != DEV_BSIZE) {
667 		DBGME(3,printf("ace%d: error reading disk label\n", unit));
668 		goto bad;
669 	}
670 	msg = getdisklabel(buf, lp);
671 	if (msg) {
672 		/* If no label, just assume 0 and return */
673 		return (0);
674 	}
675 
676 	if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) {
677 	bad:
678 		dealloc(sc, sizeof(struct ace_softc));
679 		DBGME(3,printf("ace%d: bad part %d\n", unit, part));
680 		return (ENXIO);
681 	}
682 	return (0);
683 }
684 
685 #ifndef LIBSA_NO_DEV_CLOSE
686 int
687 aceclose(struct open_file *f)
688 {
689 	dealloc(f->f_devdata, sizeof(struct ace_softc));
690 	f->f_devdata = (void *)0;
691 	return (0);
692 }
693 #endif
694 
695 int
696 acestrategy(
697 	void *devdata,
698 	int rw,
699 	daddr_t bn,
700 	size_t reqcnt,
701 	void *addr,
702 	size_t *cnt)	/* out: number of bytes transfered */
703 {
704 	struct ace_softc *sc = (struct ace_softc *)devdata;
705 	int part = sc->sc_part;
706 	struct partition *pp = &sc->sc_label.d_partitions[part];
707 	int s;
708 	uint32_t sector;
709 
710 #if 0 //useless?
711     if (rw != F_READ)
712         return (EINVAL);
713 #endif
714 
715 	/*
716 	 * Partial-block transfers not handled.
717 	 */
718 	if (reqcnt & (DEV_BSIZE - 1)) {
719 		*cnt = 0;
720 		return (EINVAL);
721 	}
722 
723     /*
724      * Compute starting sector
725      */
726 	sector = bn;
727 	sector += pp->p_offset;
728 	if (pp->p_fstype == FS_RAID)
729 		sector += RF_PROTECTED_SECTORS;
730 
731     /* read */
732     s = SysAce_read(sc->sc_dp,addr,sector,reqcnt >> CF_SECBITS);
733 
734 	if (s < 0)
735 		return (EIO);
736 
737     /* BUGBUG there's no validation we don't fall off the deep end */
738 	*cnt = reqcnt;
739 	return (0);
740 }
741 
742