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