123248Smckusick /* 2*32196Skarels * Copyright (c) 1982 Regents of the University of California. 323248Smckusick * All rights reserved. The Berkeley software License Agreement 423248Smckusick * specifies the terms and conditions for redistribution. 523248Smckusick * 6*32196Skarels * @(#)up.c 7.2 (Berkeley) 09/16/87 723248Smckusick */ 89974Ssam 910023Ssam /* 1010023Ssam * UNIBUS peripheral standalone driver 1110023Ssam * with ECC correction and bad block forwarding. 1210023Ssam * Also supports header operation and write 1310023Ssam * check for data and/or header. 1410023Ssam */ 15*32196Skarels #include "param.h" 16*32196Skarels #include "inode.h" 17*32196Skarels #include "fs.h" 18*32196Skarels #include "dkbad.h" 19*32196Skarels #include "vmmac.h" 209974Ssam 21*32196Skarels #include "vax/pte.h" 22*32196Skarels #include "vaxuba/upreg.h" 23*32196Skarels #include "vaxuba/ubareg.h" 249974Ssam 2510023Ssam #include "saio.h" 269974Ssam #include "savax.h" 279974Ssam 2825443Skarels #define RETRIES 27 2925443Skarels 3010352Shelge #define MAXBADDESC 126 /* max number of bad sectors recorded */ 3110352Shelge #define SECTSIZ 512 /* sector size in bytes */ 3210352Shelge #define HDRSIZ 4 /* number of bytes in sector header */ 3311365Ssam 3410023Ssam u_short ubastd[] = { 0776700 }; 359974Ssam 3611143Ssam extern struct st upst[]; 3710023Ssam 38*32196Skarels #ifndef SMALL 3911365Ssam struct dkbad upbad[MAXNUBA*8]; /* bad sector table */ 40*32196Skarels #endif 4111365Ssam int sectsiz; /* real sector size */ 4211365Ssam 4325443Skarels struct up_softc { 4425443Skarels char gottype; 4525443Skarels char type; 4625443Skarels char debug; 4725443Skarels # define UPF_BSEDEBUG 01 /* debugging bad sector forwarding */ 4825443Skarels # define UPF_ECCDEBUG 02 /* debugging ecc correction */ 4925443Skarels int retries; 5025443Skarels int ecclim; 5125443Skarels } up_softc[MAXNUBA * 8]; 5225443Skarels 539974Ssam u_char up_offset[16] = { 549974Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 559974Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 569974Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 579974Ssam 0, 0, 0, 0 589974Ssam }; 599974Ssam 609974Ssam upopen(io) 619974Ssam register struct iob *io; 629974Ssam { 6310352Shelge register unit = io->i_unit; 6410023Ssam register struct updevice *upaddr; 6525443Skarels register struct up_softc *sc = &up_softc[unit]; 6611118Ssam register struct st *st; 679974Ssam 6811143Ssam if (io->i_boff < 0 || io->i_boff > 7) 6910023Ssam _stop("up bad unit"); 7010352Shelge upaddr = (struct updevice *)ubamem(unit, ubastd[0]); 7115067Skarels upaddr->upcs2 = unit % 8; 7211085Ssam while ((upaddr->upcs1 & UP_DVA) == 0) 739974Ssam ; 7425443Skarels if (sc->gottype == 0) { 7510023Ssam register int i; 7610023Ssam struct iob tio; 7710023Ssam 7825443Skarels sc->retries = RETRIES; 7925443Skarels sc->ecclim = 11; 8025443Skarels sc->debug = 0; 8125443Skarels sc->type = upmaptype(unit, upaddr); 8225443Skarels if (sc->type < 0) 8310023Ssam _stop("unknown drive type"); 8425443Skarels st = &upst[sc->type]; 8511143Ssam if (st->off[io->i_boff] == -1) 8611143Ssam _stop("up bad unit"); 87*32196Skarels #ifndef SMALL 8810023Ssam /* 8911365Ssam * Read in the bad sector table. 9010023Ssam */ 9110023Ssam tio = *io; 9210023Ssam tio.i_bn = st->nspc * st->ncyl - st->nsect; 939974Ssam tio.i_ma = (char *)&upbad[tio.i_unit]; 9410638Shelge tio.i_cc = sizeof (struct dkbad); 9510023Ssam tio.i_flgs |= F_RDDATA; 9610023Ssam for (i = 0; i < 5; i++) { 9710638Shelge if (upstrategy(&tio, READ) == sizeof (struct dkbad)) 9810023Ssam break; 999974Ssam tio.i_bn += 2; 1009974Ssam } 1019974Ssam if (i == 5) { 10210023Ssam printf("Unable to read bad sector table\n"); 10310352Shelge for (i = 0; i < MAXBADDESC; i++) { 10410352Shelge upbad[unit].bt_bad[i].bt_cyl = -1; 10510352Shelge upbad[unit].bt_bad[i].bt_trksec = -1; 1069974Ssam } 1079974Ssam } 108*32196Skarels #endif 10925443Skarels sc->gottype = 1; 1109974Ssam } 11125443Skarels st = &upst[sc->type]; 1129974Ssam io->i_boff = st->off[io->i_boff] * st->nspc; 11310023Ssam io->i_flgs &= ~F_TYPEMASK; 1149974Ssam } 1159974Ssam 1169974Ssam upstrategy(io, func) 1179974Ssam register struct iob *io; 1189974Ssam { 11911317Ssam int cn, tn, sn, o; 12010352Shelge register unit = io->i_unit; 1219974Ssam daddr_t bn; 1229974Ssam int recal, info, waitdry; 1239974Ssam register struct updevice *upaddr = 12410352Shelge (struct updevice *)ubamem(unit, ubastd[0]); 12525443Skarels struct up_softc *sc = &up_softc[unit]; 12625443Skarels register struct st *st = &upst[sc->type]; 12725443Skarels int doprintf = 0, error, rv = io->i_cc; 1289974Ssam 12910352Shelge sectsiz = SECTSIZ; 13011085Ssam if (io->i_flgs & (F_HDR|F_HCHECK)) 13110352Shelge sectsiz += HDRSIZ; 13211365Ssam upaddr->upcs2 = unit % 8; 1339974Ssam if ((upaddr->upds & UPDS_VV) == 0) { 1349974Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 1359974Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 1369974Ssam upaddr->upof = UPOF_FMT22; 1379974Ssam } 13825443Skarels if ((upaddr->upds & UPDS_DREADY) == 0) { 13925443Skarels printf("up%d not ready", unit); 14025443Skarels return (-1); 14125443Skarels } 1429974Ssam info = ubasetup(io, 1); 1439974Ssam upaddr->upwc = -io->i_cc / sizeof (short); 14411085Ssam recal = 0; 14511085Ssam io->i_errcnt = 0; 14611085Ssam 14710638Shelge restart: 14825443Skarels error = 0; 14911317Ssam o = io->i_cc + (upaddr->upwc * sizeof (short)); 15011317Ssam upaddr->upba = info + o; 15111317Ssam bn = io->i_bn + o / sectsiz; 15225443Skarels if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) 15311386Ssam printf("wc=%d o=%d i_bn=%d bn=%d\n", 15411365Ssam upaddr->upwc, o, io->i_bn, bn); 15510023Ssam while((upaddr->upds & UPDS_DRY) == 0) 15610023Ssam ; 15710352Shelge if (upstart(io, bn) != 0) { 15825443Skarels rv = -1; 15925443Skarels goto done; 16010352Shelge } 1619974Ssam do { 1629974Ssam DELAY(25); 1639974Ssam } while ((upaddr->upcs1 & UP_RDY) == 0); 16411085Ssam /* 16511085Ssam * If transfer has completed, free UNIBUS 16611085Ssam * resources and return transfer size. 16711085Ssam */ 16815067Skarels if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0) 16915067Skarels goto done; 17025443Skarels bn = io->i_bn + 17125443Skarels (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz; 17225443Skarels if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH)) 17325443Skarels bn--; 17425443Skarels cn = bn/st->nspc; 17525443Skarels sn = bn%st->nspc; 17625443Skarels tn = sn/st->nsect; 17725443Skarels sn = sn%st->nsect; 178*32196Skarels #ifndef SMALL 17925443Skarels if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) { 18025443Skarels printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ", 18125443Skarels bn, cn, tn, sn); 18211386Ssam printf("cs2=%b er1=%b er2=%b wc=%d\n", 18311365Ssam upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 18411386Ssam UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc); 18511365Ssam } 186*32196Skarels #endif 1879974Ssam waitdry = 0; 18811386Ssam while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz) 18910023Ssam DELAY(5); 190*32196Skarels #ifndef SMALL 19111085Ssam if (upaddr->uper1&UPER1_WLE) { 19211085Ssam /* 19311085Ssam * Give up on write locked devices immediately. 19411085Ssam */ 19511085Ssam printf("up%d: write locked\n", unit); 19625443Skarels rv = -1; 19725443Skarels goto done; 19811085Ssam } 19925443Skarels if (upaddr->uper2 & UPER2_BSE) { 20025443Skarels if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0) 20125443Skarels goto success; 20225443Skarels error = EBSE; 20325443Skarels goto hard; 20425443Skarels } 20525443Skarels /* 20625443Skarels * ECC error. If a soft error, correct it; 20725443Skarels * if correction is too large, no more retries. 20825443Skarels */ 20925443Skarels if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) { 21025443Skarels if (upecc(io, ECC) == 0) 21125443Skarels goto success; 21225443Skarels error = EECC; 21325443Skarels goto hard; 21425443Skarels } 21525443Skarels /* 21625443Skarels * If the error is a header CRC, 21725443Skarels * check if a replacement sector exists in 21825443Skarels * the bad sector table. 21925443Skarels */ 22025443Skarels if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 && 22125443Skarels upecc(io, BSE) == 0) 22225443Skarels goto success; 223*32196Skarels #endif 22425443Skarels if (++io->i_errcnt > sc->retries) { 2259974Ssam /* 2269974Ssam * After 28 retries (16 without offset, and 2279974Ssam * 12 with offset positioning) give up. 2289974Ssam */ 22910352Shelge hard: 23025443Skarels if (error == 0) { 23125443Skarels error = EHER; 23225443Skarels if (upaddr->upcs2 & UPCS2_WCE) 23325443Skarels error = EWCK; 23425443Skarels } 23525443Skarels printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ", 23625443Skarels bn, cn, tn, sn); 23725443Skarels printf("cs2=%b er1=%b er2=%b\n", 23811085Ssam upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 23911085Ssam UPER1_BITS, upaddr->uper2, UPER2_BITS); 2409974Ssam upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 24110352Shelge io->i_errblk = bn; 24215067Skarels if (io->i_errcnt >= 16) { 24315067Skarels upaddr->upof = UPOF_FMT22; 24415067Skarels upaddr->upcs1 = UP_RTC|UP_GO; 24515067Skarels while ((upaddr->upds&UPDS_DRY) == 0) 24615067Skarels DELAY(25); 24715067Skarels } 24825443Skarels rv = -1; 24925443Skarels goto done; 25011085Ssam } 25111085Ssam /* 2529974Ssam * Clear drive error and, every eight attempts, 2539974Ssam * (starting with the fourth) 2549974Ssam * recalibrate to clear the slate. 2559974Ssam */ 2569974Ssam upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 25710638Shelge if ((io->i_errcnt&07) == 4 ) { 2589974Ssam upaddr->upcs1 = UP_RECAL|UP_GO; 25915067Skarels while ((upaddr->upds&UPDS_DRY) == 0) 26015067Skarels DELAY(25); 2619974Ssam upaddr->updc = cn; 2629974Ssam upaddr->upcs1 = UP_SEEK|UP_GO; 26315067Skarels while ((upaddr->upds&UPDS_DRY) == 0) 26415067Skarels DELAY(25); 26515067Skarels } 26615067Skarels if (io->i_errcnt >= 16 && (func & READ)) { 2679974Ssam upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22; 2689974Ssam upaddr->upcs1 = UP_OFFSET|UP_GO; 26910638Shelge while ((upaddr->upds&UPDS_DRY) == 0) 27010638Shelge DELAY(25); 2719974Ssam } 27210638Shelge goto restart; 27311085Ssam 2749974Ssam success: 27511386Ssam #define rounddown(x, y) (((x) / (y)) * (y)) 27611386Ssam upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short)); 27711386Ssam if (upaddr->upwc) { 27811317Ssam doprintf++; 27910638Shelge goto restart; 28011317Ssam } 28115067Skarels done: 2829974Ssam /* 28311365Ssam * Release UNIBUS 2849974Ssam */ 2859974Ssam ubafree(io, info); 28615067Skarels /* 28715067Skarels * If we were offset positioning, 28815067Skarels * return to centerline. 28915067Skarels */ 29015067Skarels if (io->i_errcnt >= 16) { 29115067Skarels upaddr->upof = UPOF_FMT22; 29215067Skarels upaddr->upcs1 = UP_RTC|UP_GO; 29315067Skarels while ((upaddr->upds&UPDS_DRY) == 0) 29415067Skarels DELAY(25); 29515067Skarels } 29625443Skarels return (rv); 2979974Ssam } 2989974Ssam 299*32196Skarels #ifndef SMALL 3009974Ssam /* 30111143Ssam * Correct an ECC error, and restart the 30211143Ssam * i/o to complete the transfer (if necessary). 30311143Ssam * This is quite complicated because the transfer 30411143Ssam * may be going to an odd memory address base and/or 3059974Ssam * across a page boundary. 3069974Ssam */ 30710023Ssam upecc(io, flag) 3089974Ssam register struct iob *io; 3099974Ssam int flag; 3109974Ssam { 31111365Ssam register i, unit = io->i_unit; 31225443Skarels register struct up_softc *sc = &up_softc[unit]; 3139974Ssam register struct updevice *up = 31411365Ssam (struct updevice *)ubamem(unit, ubastd[0]); 31510352Shelge register struct st *st; 3169974Ssam caddr_t addr; 31710410Shelge int bn, twc, npf, mask, cn, tn, sn; 31810352Shelge daddr_t bbn; 3199974Ssam 3209974Ssam /* 32111143Ssam * Npf is the number of sectors transferred 32211143Ssam * before the sector containing the ECC error; 32311143Ssam * bn is the current block number. 3249974Ssam */ 32510352Shelge twc = up->upwc; 32611143Ssam npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz; 32715067Skarels if (flag == ECC) 32815067Skarels npf--; 32925443Skarels if (sc->debug & UPF_ECCDEBUG) 33011386Ssam printf("npf=%d mask=0x%x ec1=%d wc=%d\n", 33111386Ssam npf, up->upec2, up->upec1, twc); 33211317Ssam bn = io->i_bn + npf; 33325443Skarels st = &upst[sc->type]; 33410410Shelge cn = bn/st->nspc; 33510410Shelge sn = bn%st->nspc; 33610410Shelge tn = sn/st->nsect; 33710410Shelge sn = sn%st->nsect; 33811143Ssam 3399974Ssam /* 34011143Ssam * ECC correction. 3419974Ssam */ 3429974Ssam if (flag == ECC) { 34325443Skarels int bit, o; 34411085Ssam 3459974Ssam mask = up->upec2; 34611365Ssam printf("up%d: soft ecc sn%d\n", unit, bn); 34725443Skarels for (i = mask, bit = 0; i; i >>= 1) 34825443Skarels if (i & 1) 34925443Skarels bit++; 35025443Skarels if (bit > sc->ecclim) { 35125443Skarels printf("%d-bit error\n", bit); 35225443Skarels return (1); 35325443Skarels } 3549974Ssam /* 35511317Ssam * Compute the byte and bit position of 35611317Ssam * the error. o is the byte offset in 35711317Ssam * the transfer at which the correction 35811317Ssam * applied. 3599974Ssam */ 3609974Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 36111386Ssam bit = i & 07; 36211386Ssam o = (i & ~07) >> 3; 3639974Ssam up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 3649974Ssam /* 36511143Ssam * Correct while possible bits remain of mask. 36611143Ssam * Since mask contains 11 bits, we continue while 36711143Ssam * the bit offset is > -11. Also watch out for 36811143Ssam * end of this block and the end of the transfer. 3699974Ssam */ 37011317Ssam while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) { 3719974Ssam /* 37211143Ssam * addr = 37311317Ssam * (base address of transfer) + 37411143Ssam * (# sectors transferred before the error) * 37511143Ssam * (sector size) + 37611317Ssam * (byte offset to incorrect data) 3779974Ssam */ 37811317Ssam addr = io->i_ma + (npf * sectsiz) + o; 37911317Ssam /* 38011317Ssam * No data transfer occurs with a write check, 38111317Ssam * so don't correct the resident copy of data. 38211317Ssam */ 38311365Ssam if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { 38425443Skarels if (sc->debug & UPF_ECCDEBUG) 38511365Ssam printf("addr=0x%x old=0x%x ", addr, 38611365Ssam (*addr&0xff)); 38710352Shelge *addr ^= (mask << bit); 38825443Skarels if (sc->debug & UPF_ECCDEBUG) 38911365Ssam printf("new=0x%x\n", (*addr&0xff)); 39011365Ssam } 39111317Ssam o++, bit -= 8; 3929974Ssam } 39311085Ssam return (0); 39411085Ssam } 39511143Ssam 39611143Ssam /* 39711143Ssam * Bad sector forwarding. 39811143Ssam */ 39911085Ssam if (flag == BSE) { 4009974Ssam /* 40111143Ssam * If not in bad sector table, 40211143Ssam * indicate a hard error to caller. 4039974Ssam */ 40410352Shelge up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 40511365Ssam if ((bbn = isbad(&upbad[unit], cn, tn, sn)) < 0) 40611085Ssam return (1); 40711386Ssam bbn = (st->ncyl * st->nspc) - st->nsect - 1 - bbn; 40810352Shelge twc = up->upwc + sectsiz; 40911085Ssam up->upwc = - (sectsiz / sizeof (short)); 41025443Skarels if (sc->debug & UPF_BSEDEBUG) 41111365Ssam printf("revector sn %d to %d\n", sn, bbn); 4129974Ssam /* 41311143Ssam * Clear the drive & read the replacement 41411143Ssam * sector. If this is in the middle of a 41511143Ssam * transfer, then set up the controller 41611143Ssam * registers in a normal fashion. 41711143Ssam * The UNIBUS address need not be changed. 41811143Ssam */ 41911386Ssam while ((up->upcs1 & UP_RDY) == 0) 4209974Ssam ; 42111386Ssam if (upstart(io, bbn)) 42210352Shelge return (1); /* error */ 42310352Shelge io->i_errcnt = 0; /* success */ 4249974Ssam do { 4259974Ssam DELAY(25); 42611386Ssam } while ((up->upcs1 & UP_RDY) == 0) ; 42711386Ssam if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) { 42811386Ssam up->upwc = twc - sectsiz; 42910352Shelge return (1); 4309974Ssam } 4319974Ssam } 43210638Shelge if (twc) 4339974Ssam up->upwc = twc; 43410352Shelge return (0); 4359974Ssam } 436*32196Skarels #endif 4379974Ssam 4389974Ssam upstart(io, bn) 43910023Ssam register struct iob *io; 44010023Ssam daddr_t bn; 4419974Ssam { 4429974Ssam register struct updevice *upaddr = 44310023Ssam (struct updevice *)ubamem(io->i_unit, ubastd[0]); 44425443Skarels register struct up_softc *sc = &up_softc[io->i_unit]; 44525443Skarels register struct st *st = &upst[sc->type]; 4469974Ssam int sn, tn; 4479974Ssam 4489974Ssam sn = bn%st->nspc; 4499974Ssam tn = sn/st->nsect; 4509974Ssam sn %= st->nsect; 4519974Ssam upaddr->updc = bn/st->nspc; 4529974Ssam upaddr->upda = (tn << 8) + sn; 45310352Shelge switch (io->i_flgs & F_TYPEMASK) { 45410023Ssam 45510023Ssam case F_RDDATA: 45610023Ssam upaddr->upcs1 = UP_RCOM|UP_GO; 4579974Ssam break; 45810023Ssam 45910023Ssam case F_WRDATA: 46010023Ssam upaddr->upcs1 = UP_WCOM|UP_GO; 4619974Ssam break; 46210023Ssam 463*32196Skarels #ifndef SMALL 46410023Ssam case F_HDR|F_RDDATA: 46510023Ssam upaddr->upcs1 = UP_RHDR|UP_GO; 46610023Ssam break; 46710023Ssam 46810023Ssam case F_HDR|F_WRDATA: 46910023Ssam upaddr->upcs1 = UP_WHDR|UP_GO; 47010023Ssam break; 47110023Ssam 47210023Ssam case F_CHECK|F_WRDATA: 47310023Ssam case F_CHECK|F_RDDATA: 4749974Ssam upaddr->upcs1 = UP_WCDATA|UP_GO; 4759974Ssam break; 47610023Ssam 47710023Ssam case F_HCHECK|F_WRDATA: 47810023Ssam case F_HCHECK|F_RDDATA: 4799974Ssam upaddr->upcs1 = UP_WCHDR|UP_GO; 4809974Ssam break; 481*32196Skarels #endif 48210023Ssam 4839974Ssam default: 48410023Ssam io->i_error = ECMD; 48510023Ssam io->i_flgs &= ~F_TYPEMASK; 48610023Ssam return (1); 4879974Ssam } 48810023Ssam return (0); 4899974Ssam } 4909974Ssam 49110023Ssam /*ARGSUSED*/ 49210023Ssam upioctl(io, cmd, arg) 49310023Ssam struct iob *io; 49410023Ssam int cmd; 49510023Ssam caddr_t arg; 49610023Ssam { 497*32196Skarels #ifndef SMALL 49825443Skarels int unit = io->i_unit; 49925443Skarels register struct up_softc *sc = &up_softc[unit]; 50025443Skarels struct st *st = &upst[sc->type]; 50110352Shelge 50210352Shelge switch(cmd) { 50310352Shelge 50411365Ssam case SAIODEBUG: 50525443Skarels sc->debug = (int)arg; 50625443Skarels break; 50711365Ssam 50810352Shelge case SAIODEVDATA: 50925443Skarels *(struct st *)arg = *st; 51025443Skarels break; 51125443Skarels 51225443Skarels case SAIOGBADINFO: 51325443Skarels *(struct dkbad *)arg = upbad[unit]; 51425443Skarels break; 51525443Skarels 51625443Skarels case SAIOECCLIM: 51725443Skarels sc->ecclim = (int)arg; 51825443Skarels break; 51925443Skarels 52025443Skarels case SAIORETRIES: 52125443Skarels sc->retries = (int)arg; 52225443Skarels break; 52325443Skarels 52425443Skarels default: 52525443Skarels return (ECMD); 52610352Shelge } 52725443Skarels return (0); 528*32196Skarels #else SMALL 529*32196Skarels return (ECMD); 530*32196Skarels #endif 53110023Ssam } 532