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