14de34a7eSDavid du Colombier /*
257195852SDavid du Colombier * Marvell 88SX[56]0[48][01] fileserver Serial ATA (SATA) driver
357195852SDavid du Colombier *
457195852SDavid du Colombier * See MV-S101357-00 Rev B Marvell PCI/PCI-X to 8-Port/4-Port
557195852SDavid du Colombier * SATA Host Controller, ATA-5 ANSI NCITS 340-2000.
657195852SDavid du Colombier *
757195852SDavid du Colombier * This is a heavily-modified version (by Coraid) of a heavily-modified
857195852SDavid du Colombier * version (from The Labs) of a driver written by Coraid, Inc.
94de34a7eSDavid du Colombier * The original copyright notice appears at the end of this file.
104de34a7eSDavid du Colombier */
114de34a7eSDavid du Colombier
124de34a7eSDavid du Colombier #include "u.h"
134de34a7eSDavid du Colombier #include "../port/lib.h"
144de34a7eSDavid du Colombier #include "mem.h"
154de34a7eSDavid du Colombier #include "dat.h"
164de34a7eSDavid du Colombier #include "fns.h"
174de34a7eSDavid du Colombier #include "io.h"
184de34a7eSDavid du Colombier #include "../port/error.h"
194de34a7eSDavid du Colombier
204de34a7eSDavid du Colombier #include "../port/sd.h"
214de34a7eSDavid du Colombier
2257195852SDavid du Colombier #define dprint if(!0){}else iprint
2357195852SDavid du Colombier #define idprint if(!0){}else iprint
2457195852SDavid du Colombier #define ioprint if(!0){}else iprint
2557195852SDavid du Colombier
2657195852SDavid du Colombier enum {
2757195852SDavid du Colombier NCtlr = 4,
2857195852SDavid du Colombier NCtlrdrv = 8,
2957195852SDavid du Colombier NDrive = NCtlr*NCtlrdrv,
3057195852SDavid du Colombier
3157195852SDavid du Colombier Read = 0,
3257195852SDavid du Colombier Write,
33*ea58ad6fSDavid du Colombier
34*ea58ad6fSDavid du Colombier Coraiddebug = 0,
3557195852SDavid du Colombier };
364de34a7eSDavid du Colombier
374de34a7eSDavid du Colombier enum {
384de34a7eSDavid du Colombier SrbRing = 32,
394de34a7eSDavid du Colombier
404de34a7eSDavid du Colombier /* Addresses of ATA register */
414de34a7eSDavid du Colombier ARcmd = 027,
424de34a7eSDavid du Colombier ARdev = 026,
434de34a7eSDavid du Colombier ARerr = 021,
444de34a7eSDavid du Colombier ARfea = 021,
454de34a7eSDavid du Colombier ARlba2 = 025,
464de34a7eSDavid du Colombier ARlba1 = 024,
474de34a7eSDavid du Colombier ARlba0 = 023,
484de34a7eSDavid du Colombier ARseccnt = 022,
494de34a7eSDavid du Colombier ARstat = 027,
504de34a7eSDavid du Colombier
514de34a7eSDavid du Colombier ATAerr = (1<<0),
524de34a7eSDavid du Colombier ATAdrq = (1<<3),
534de34a7eSDavid du Colombier ATAdf = (1<<5),
544de34a7eSDavid du Colombier ATAdrdy = (1<<6),
554de34a7eSDavid du Colombier ATAbusy = (1<<7),
564de34a7eSDavid du Colombier ATAabort = (1<<2),
5757195852SDavid du Colombier ATAobs = (1<<1 | 1<<2 | 1<<4),
584de34a7eSDavid du Colombier ATAeIEN = (1<<1),
594de34a7eSDavid du Colombier ATAsrst = (1<<2),
604de34a7eSDavid du Colombier ATAhob = (1<<7),
6157195852SDavid du Colombier ATAbad = (ATAbusy|ATAdf|ATAdrq|ATAerr),
624de34a7eSDavid du Colombier
634de34a7eSDavid du Colombier SFdone = (1<<0),
644de34a7eSDavid du Colombier SFerror = (1<<1),
654de34a7eSDavid du Colombier
664de34a7eSDavid du Colombier SRBident = 0,
674de34a7eSDavid du Colombier SRBread,
684de34a7eSDavid du Colombier SRBwrite,
694de34a7eSDavid du Colombier SRBsmart,
704de34a7eSDavid du Colombier
714de34a7eSDavid du Colombier SRBnodata = 0,
724de34a7eSDavid du Colombier SRBdatain,
734de34a7eSDavid du Colombier SRBdataout,
744de34a7eSDavid du Colombier
754de34a7eSDavid du Colombier RQread = 1, /* data coming IN from device */
764de34a7eSDavid du Colombier
774de34a7eSDavid du Colombier PRDeot = (1<<15),
784de34a7eSDavid du Colombier
794de34a7eSDavid du Colombier /* EDMA interrupt error cause register */
804de34a7eSDavid du Colombier
814de34a7eSDavid du Colombier ePrtDataErr = (1<<0),
824de34a7eSDavid du Colombier ePrtPRDErr = (1<<1),
834de34a7eSDavid du Colombier eDevErr = (1<<2),
844de34a7eSDavid du Colombier eDevDis = (1<<3),
854de34a7eSDavid du Colombier eDevCon = (1<<4),
864de34a7eSDavid du Colombier eOverrun = (1<<5),
874de34a7eSDavid du Colombier eUnderrun = (1<<6),
884de34a7eSDavid du Colombier eSelfDis = (1<<8),
894de34a7eSDavid du Colombier ePrtCRQBErr = (1<<9),
904de34a7eSDavid du Colombier ePrtCRPBErr = (1<<10),
914de34a7eSDavid du Colombier ePrtIntErr = (1<<11),
924de34a7eSDavid du Colombier eIORdyErr = (1<<12),
934de34a7eSDavid du Colombier
9441dd6b47SDavid du Colombier /* flags for sata 2 version */
9557195852SDavid du Colombier eSelfDis2 = (1<<7),
9657195852SDavid du Colombier SerrInt = (1<<5),
9757195852SDavid du Colombier
984de34a7eSDavid du Colombier /* EDMA Command Register */
994de34a7eSDavid du Colombier
1004de34a7eSDavid du Colombier eEnEDMA = (1<<0),
1014de34a7eSDavid du Colombier eDsEDMA = (1<<1),
1024de34a7eSDavid du Colombier eAtaRst = (1<<2),
1034de34a7eSDavid du Colombier
1044de34a7eSDavid du Colombier /* Interrupt mask for errors we care about */
1054de34a7eSDavid du Colombier IEM = (eDevDis | eDevCon | eSelfDis),
10657195852SDavid du Colombier IEM2 = (eDevDis | eDevCon | eSelfDis2),
1074de34a7eSDavid du Colombier
10857195852SDavid du Colombier /* drive states */
1094de34a7eSDavid du Colombier Dnull = 0,
1104de34a7eSDavid du Colombier Dnew,
1114de34a7eSDavid du Colombier Dready,
1124de34a7eSDavid du Colombier Derror,
1134de34a7eSDavid du Colombier Dmissing,
11457195852SDavid du Colombier Dreset,
11557195852SDavid du Colombier Dlast,
1164de34a7eSDavid du Colombier
11757195852SDavid du Colombier /* drive flags */
1184de34a7eSDavid du Colombier Dext = (1<<0), /* use ext commands */
1194de34a7eSDavid du Colombier Dpio = (1<<1), /* doing pio */
1204de34a7eSDavid du Colombier Dwanted = (1<<2), /* someone wants an srb entry */
1214de34a7eSDavid du Colombier Dedma = (1<<3), /* device in edma mode */
1224de34a7eSDavid du Colombier Dpiowant = (1<<4), /* some wants to use the pio mode */
12357195852SDavid du Colombier
12441dd6b47SDavid du Colombier /* phyerrata magic crap */
12557195852SDavid du Colombier Mpreamp = 0x7e0,
12657195852SDavid du Colombier Dpreamp = 0x720,
12757195852SDavid du Colombier
12857195852SDavid du Colombier REV60X1B2 = 0x7,
12957195852SDavid du Colombier REV60X1C0 = 0x9,
13057195852SDavid du Colombier
1314de34a7eSDavid du Colombier };
1324de34a7eSDavid du Colombier
13357195852SDavid du Colombier static char* diskstates[Dlast] = {
1344de34a7eSDavid du Colombier "null",
1354de34a7eSDavid du Colombier "new",
1364de34a7eSDavid du Colombier "ready",
1374de34a7eSDavid du Colombier "error",
1384de34a7eSDavid du Colombier "missing",
13957195852SDavid du Colombier "reset",
1404de34a7eSDavid du Colombier };
1414de34a7eSDavid du Colombier
1424de34a7eSDavid du Colombier extern SDifc sdmv50xxifc;
1434de34a7eSDavid du Colombier
1444de34a7eSDavid du Colombier typedef struct Arb Arb;
1454de34a7eSDavid du Colombier typedef struct Bridge Bridge;
1464de34a7eSDavid du Colombier typedef struct Chip Chip;
1474de34a7eSDavid du Colombier typedef struct Ctlr Ctlr;
1484de34a7eSDavid du Colombier typedef struct Drive Drive;
1494de34a7eSDavid du Colombier typedef struct Edma Edma;
1504de34a7eSDavid du Colombier typedef struct Prd Prd;
1514de34a7eSDavid du Colombier typedef struct Rx Rx;
1524de34a7eSDavid du Colombier typedef struct Srb Srb;
1534de34a7eSDavid du Colombier typedef struct Tx Tx;
1544de34a7eSDavid du Colombier
15541dd6b47SDavid du Colombier /*
15641dd6b47SDavid du Colombier * there are 4 drives per chip. thus an 8-port
15741dd6b47SDavid du Colombier * card has two chips.
15841dd6b47SDavid du Colombier */
15957195852SDavid du Colombier struct Chip
1604de34a7eSDavid du Colombier {
1614de34a7eSDavid du Colombier Arb *arb;
16257195852SDavid du Colombier Edma *edma;
1634de34a7eSDavid du Colombier };
1644de34a7eSDavid du Colombier
16557195852SDavid du Colombier enum {
16657195852SDavid du Colombier DMautoneg,
16757195852SDavid du Colombier DMsatai,
16857195852SDavid du Colombier DMsataii,
16957195852SDavid du Colombier };
17057195852SDavid du Colombier
17157195852SDavid du Colombier struct Drive
1724de34a7eSDavid du Colombier {
1734de34a7eSDavid du Colombier Lock;
1744de34a7eSDavid du Colombier
1754de34a7eSDavid du Colombier Ctlr *ctlr;
1764de34a7eSDavid du Colombier SDunit *unit;
1774de34a7eSDavid du Colombier char name[10];
17857195852SDavid du Colombier ulong magic;
1794de34a7eSDavid du Colombier
1804de34a7eSDavid du Colombier Bridge *bridge;
1814de34a7eSDavid du Colombier Edma *edma;
1824de34a7eSDavid du Colombier Chip *chip;
1834de34a7eSDavid du Colombier int chipx;
1844de34a7eSDavid du Colombier
18557195852SDavid du Colombier int mediachange;
1864de34a7eSDavid du Colombier int state;
1874de34a7eSDavid du Colombier int flag;
1884de34a7eSDavid du Colombier uvlong sectors;
18941dd6b47SDavid du Colombier ulong pm2; /* phymode 2 init state */
19041dd6b47SDavid du Colombier ulong intick; /* check for hung western digital drives. */
19157195852SDavid du Colombier int wait;
19241dd6b47SDavid du Colombier int mode; /* DMautoneg, satai or sataii. */
1934de34a7eSDavid du Colombier
1944de34a7eSDavid du Colombier char serial[20+1];
1954de34a7eSDavid du Colombier char firmware[8+1];
1964de34a7eSDavid du Colombier char model[40+1];
1974de34a7eSDavid du Colombier
1984de34a7eSDavid du Colombier ushort info[256];
1994de34a7eSDavid du Colombier
2004de34a7eSDavid du Colombier Srb *srb[SrbRing-1];
2014de34a7eSDavid du Colombier int nsrb;
2024de34a7eSDavid du Colombier Prd *prd;
2034de34a7eSDavid du Colombier Tx *tx;
2044de34a7eSDavid du Colombier Rx *rx;
2054de34a7eSDavid du Colombier
2064de34a7eSDavid du Colombier Srb *srbhead;
2074de34a7eSDavid du Colombier Srb *srbtail;
20841dd6b47SDavid du Colombier int driveno; /* ctlr*NCtlrdrv + unit */
2094de34a7eSDavid du Colombier };
2104de34a7eSDavid du Colombier
21157195852SDavid du Colombier struct Ctlr
2124de34a7eSDavid du Colombier {
2134de34a7eSDavid du Colombier Lock;
2144de34a7eSDavid du Colombier
2154de34a7eSDavid du Colombier int irq;
2164de34a7eSDavid du Colombier int tbdf;
21757195852SDavid du Colombier int rid;
21857195852SDavid du Colombier ulong magic;
21957195852SDavid du Colombier int enabled;
22057195852SDavid du Colombier int type;
2214de34a7eSDavid du Colombier SDev *sdev;
2224de34a7eSDavid du Colombier Pcidev *pcidev;
2234de34a7eSDavid du Colombier
2244de34a7eSDavid du Colombier uchar *mmio;
22557195852SDavid du Colombier ulong *lmmio;
2264de34a7eSDavid du Colombier Chip chip[2];
2274de34a7eSDavid du Colombier int nchip;
22857195852SDavid du Colombier Drive drive[NCtlrdrv];
2294de34a7eSDavid du Colombier int ndrive;
2304de34a7eSDavid du Colombier };
2314de34a7eSDavid du Colombier
2324de34a7eSDavid du Colombier struct Srb /* request buffer */
2334de34a7eSDavid du Colombier {
2344de34a7eSDavid du Colombier Lock;
2354de34a7eSDavid du Colombier Rendez;
2364de34a7eSDavid du Colombier Srb *next;
2374de34a7eSDavid du Colombier
2384de34a7eSDavid du Colombier Drive *drive;
2394de34a7eSDavid du Colombier uvlong blockno;
2404de34a7eSDavid du Colombier int count;
2414de34a7eSDavid du Colombier int req;
2424de34a7eSDavid du Colombier int flag;
2434de34a7eSDavid du Colombier uchar *data;
2444de34a7eSDavid du Colombier
2454de34a7eSDavid du Colombier uchar cmd;
2464de34a7eSDavid du Colombier uchar lba[6];
2474de34a7eSDavid du Colombier uchar sectors;
2484de34a7eSDavid du Colombier int sta;
2494de34a7eSDavid du Colombier int err;
2504de34a7eSDavid du Colombier };
2514de34a7eSDavid du Colombier
2524de34a7eSDavid du Colombier /*
2534de34a7eSDavid du Colombier * Memory-mapped I/O registers in many forms.
2544de34a7eSDavid du Colombier */
2554de34a7eSDavid du Colombier struct Bridge /* memory-mapped per-Drive registers */
2564de34a7eSDavid du Colombier {
2574de34a7eSDavid du Colombier ulong status;
2584de34a7eSDavid du Colombier ulong serror;
2594de34a7eSDavid du Colombier ulong sctrl;
2604de34a7eSDavid du Colombier ulong phyctrl;
26157195852SDavid du Colombier ulong phymode3;
26257195852SDavid du Colombier ulong phymode4;
26357195852SDavid du Colombier uchar fill0[0x14];
26457195852SDavid du Colombier ulong phymode1;
26557195852SDavid du Colombier ulong phymode2;
26657195852SDavid du Colombier char fill1[8];
2674de34a7eSDavid du Colombier ulong ctrl;
2684de34a7eSDavid du Colombier char fill2[0x34];
2694de34a7eSDavid du Colombier ulong phymode;
27057195852SDavid du Colombier char fill3[0x88];
27141dd6b47SDavid du Colombier }; /* length must be 0x100 */
2724de34a7eSDavid du Colombier
2734de34a7eSDavid du Colombier struct Arb /* memory-mapped per-Chip registers */
2744de34a7eSDavid du Colombier {
27557195852SDavid du Colombier ulong config; /* satahc configuration register (sata2 only) */
2764de34a7eSDavid du Colombier ulong rqop; /* request queue out-pointer */
2774de34a7eSDavid du Colombier ulong rqip; /* response queue in pointer */
2784de34a7eSDavid du Colombier ulong ict; /* inerrupt caolescing threshold */
2794de34a7eSDavid du Colombier ulong itt; /* interrupt timer threshold */
2804de34a7eSDavid du Colombier ulong ic; /* interrupt cause */
2814de34a7eSDavid du Colombier ulong btc; /* bridges test control */
2824de34a7eSDavid du Colombier ulong bts; /* bridges test status */
2834de34a7eSDavid du Colombier ulong bpc; /* bridges pin configuration */
2844de34a7eSDavid du Colombier char fill1[0xdc];
2854de34a7eSDavid du Colombier Bridge bridge[4];
2864de34a7eSDavid du Colombier };
2874de34a7eSDavid du Colombier
2884de34a7eSDavid du Colombier struct Edma /* memory-mapped per-Drive DMA-related registers */
2894de34a7eSDavid du Colombier {
2904de34a7eSDavid du Colombier ulong config; /* configuration register */
2914de34a7eSDavid du Colombier ulong timer;
2924de34a7eSDavid du Colombier ulong iec; /* interrupt error cause */
2934de34a7eSDavid du Colombier ulong iem; /* interrupt error mask */
2944de34a7eSDavid du Colombier
2954de34a7eSDavid du Colombier ulong txbasehi; /* request queue base address high */
2964de34a7eSDavid du Colombier ulong txi; /* request queue in pointer */
2974de34a7eSDavid du Colombier ulong txo; /* request queue out pointer */
2984de34a7eSDavid du Colombier
2994de34a7eSDavid du Colombier ulong rxbasehi; /* response queue base address high */
3004de34a7eSDavid du Colombier ulong rxi; /* response queue in pointer */
3014de34a7eSDavid du Colombier ulong rxo; /* response queue out pointer */
3024de34a7eSDavid du Colombier
3034de34a7eSDavid du Colombier ulong ctl; /* command register */
3044de34a7eSDavid du Colombier ulong testctl; /* test control */
3054de34a7eSDavid du Colombier ulong status;
3064de34a7eSDavid du Colombier ulong iordyto; /* IORDY timeout */
30757195852SDavid du Colombier char fill[0x18];
30857195852SDavid du Colombier ulong sataconfig; /* sata 2 */
30957195852SDavid du Colombier char fill[0xac];
3104de34a7eSDavid du Colombier ushort pio; /* data register */
3114de34a7eSDavid du Colombier char pad0[2];
3124de34a7eSDavid du Colombier uchar err; /* features and error */
3134de34a7eSDavid du Colombier char pad1[3];
3144de34a7eSDavid du Colombier uchar seccnt; /* sector count */
3154de34a7eSDavid du Colombier char pad2[3];
3164de34a7eSDavid du Colombier uchar lba0;
3174de34a7eSDavid du Colombier char pad3[3];
3184de34a7eSDavid du Colombier uchar lba1;
3194de34a7eSDavid du Colombier char pad4[3];
3204de34a7eSDavid du Colombier uchar lba2;
3214de34a7eSDavid du Colombier char pad5[3];
3224de34a7eSDavid du Colombier uchar lba3;
3234de34a7eSDavid du Colombier char pad6[3];
3244de34a7eSDavid du Colombier uchar cmdstat; /* cmd/status */
3254de34a7eSDavid du Colombier char pad7[3];
3264de34a7eSDavid du Colombier uchar altstat; /* alternate status */
32757195852SDavid du Colombier uchar fill2[0x1df];
32857195852SDavid du Colombier Bridge port;
32957195852SDavid du Colombier char fill3[0x1c00]; /* pad to 0x2000 bytes */
3304de34a7eSDavid du Colombier };
3314de34a7eSDavid du Colombier
3324de34a7eSDavid du Colombier /*
3334de34a7eSDavid du Colombier * Memory structures shared with card.
3344de34a7eSDavid du Colombier */
3354de34a7eSDavid du Colombier struct Prd /* physical region descriptor */
3364de34a7eSDavid du Colombier {
3374de34a7eSDavid du Colombier ulong pa; /* byte address of physical memory */
3384de34a7eSDavid du Colombier ushort count; /* byte count (bit0 must be 0) */
3394de34a7eSDavid du Colombier ushort flag;
3404de34a7eSDavid du Colombier ulong zero; /* high long of 64 bit address */
3414de34a7eSDavid du Colombier ulong reserved;
3424de34a7eSDavid du Colombier };
3434de34a7eSDavid du Colombier
3444de34a7eSDavid du Colombier struct Tx /* command request block */
3454de34a7eSDavid du Colombier {
3464de34a7eSDavid du Colombier ulong prdpa; /* physical region descriptor table structures */
3474de34a7eSDavid du Colombier ulong zero; /* must be zero (high long of prd address) */
3484de34a7eSDavid du Colombier ushort flag; /* control flags */
3494de34a7eSDavid du Colombier ushort regs[11];
3504de34a7eSDavid du Colombier };
3514de34a7eSDavid du Colombier
3524de34a7eSDavid du Colombier struct Rx /* command response block */
3534de34a7eSDavid du Colombier {
3544de34a7eSDavid du Colombier ushort cid; /* cID of response */
3554de34a7eSDavid du Colombier uchar cEdmaSts; /* EDMA status */
3564de34a7eSDavid du Colombier uchar cDevSts; /* status from disk */
3574de34a7eSDavid du Colombier ulong ts; /* time stamp */
3584de34a7eSDavid du Colombier };
3594de34a7eSDavid du Colombier
36057195852SDavid du Colombier static Drive *mvsatadrive[NDrive];
36157195852SDavid du Colombier static int nmvsatadrive;
36257195852SDavid du Colombier
3634de34a7eSDavid du Colombier /*
3644de34a7eSDavid du Colombier * Little-endian parsing for drive data.
3654de34a7eSDavid du Colombier */
3664de34a7eSDavid du Colombier static ushort
lhgets(void * p)3674de34a7eSDavid du Colombier lhgets(void *p)
3684de34a7eSDavid du Colombier {
3694de34a7eSDavid du Colombier uchar *a = p;
3704de34a7eSDavid du Colombier return ((ushort) a[1] << 8) | a[0];
3714de34a7eSDavid du Colombier }
3724de34a7eSDavid du Colombier
3734de34a7eSDavid du Colombier static ulong
lhgetl(void * p)3744de34a7eSDavid du Colombier lhgetl(void *p)
3754de34a7eSDavid du Colombier {
3764de34a7eSDavid du Colombier uchar *a = p;
3774de34a7eSDavid du Colombier return ((ulong) lhgets(a+2) << 16) | lhgets(a);
3784de34a7eSDavid du Colombier }
3794de34a7eSDavid du Colombier
3804de34a7eSDavid du Colombier static uvlong
lhgetv(void * p)3814de34a7eSDavid du Colombier lhgetv(void *p)
3824de34a7eSDavid du Colombier {
3834de34a7eSDavid du Colombier uchar *a = p;
3844de34a7eSDavid du Colombier return ((uvlong) lhgetl(a+4) << 32) | lhgetl(a);
3854de34a7eSDavid du Colombier }
3864de34a7eSDavid du Colombier
3874de34a7eSDavid du Colombier static void
idmove(char * p,ushort * a,int n)3884de34a7eSDavid du Colombier idmove(char *p, ushort *a, int n)
3894de34a7eSDavid du Colombier {
3904de34a7eSDavid du Colombier char *op;
3914de34a7eSDavid du Colombier int i;
3924de34a7eSDavid du Colombier
3934de34a7eSDavid du Colombier op = p;
3944de34a7eSDavid du Colombier for(i=0; i<n/2; i++){
3954de34a7eSDavid du Colombier *p++ = a[i]>>8;
3964de34a7eSDavid du Colombier *p++ = a[i];
3974de34a7eSDavid du Colombier }
3984de34a7eSDavid du Colombier while(p>op && *--p == ' ')
3994de34a7eSDavid du Colombier *p = 0;
4004de34a7eSDavid du Colombier }
4014de34a7eSDavid du Colombier
4024de34a7eSDavid du Colombier /*
4034de34a7eSDavid du Colombier * Request buffers.
4044de34a7eSDavid du Colombier */
4054de34a7eSDavid du Colombier struct
4064de34a7eSDavid du Colombier {
4074de34a7eSDavid du Colombier Lock;
4084de34a7eSDavid du Colombier Srb *freechain;
4094de34a7eSDavid du Colombier int nalloc;
4104de34a7eSDavid du Colombier } srblist;
4114de34a7eSDavid du Colombier
4124de34a7eSDavid du Colombier static Srb*
allocsrb(void)4134de34a7eSDavid du Colombier allocsrb(void)
4144de34a7eSDavid du Colombier {
4154de34a7eSDavid du Colombier Srb *p;
4164de34a7eSDavid du Colombier
4174de34a7eSDavid du Colombier ilock(&srblist);
4184de34a7eSDavid du Colombier if((p = srblist.freechain) == nil){
4194de34a7eSDavid du Colombier srblist.nalloc++;
4204de34a7eSDavid du Colombier iunlock(&srblist);
4214de34a7eSDavid du Colombier p = smalloc(sizeof *p);
4224de34a7eSDavid du Colombier }else{
4234de34a7eSDavid du Colombier srblist.freechain = p->next;
4244de34a7eSDavid du Colombier iunlock(&srblist);
4254de34a7eSDavid du Colombier }
4264de34a7eSDavid du Colombier return p;
4274de34a7eSDavid du Colombier }
4284de34a7eSDavid du Colombier
4294de34a7eSDavid du Colombier static void
freesrb(Srb * p)4304de34a7eSDavid du Colombier freesrb(Srb *p)
4314de34a7eSDavid du Colombier {
4324de34a7eSDavid du Colombier ilock(&srblist);
4334de34a7eSDavid du Colombier p->next = srblist.freechain;
4344de34a7eSDavid du Colombier srblist.freechain = p;
4354de34a7eSDavid du Colombier iunlock(&srblist);
4364de34a7eSDavid du Colombier }
4374de34a7eSDavid du Colombier
4384de34a7eSDavid du Colombier /*
4394de34a7eSDavid du Colombier * Wait for a byte to be a particular value.
4404de34a7eSDavid du Colombier */
4414de34a7eSDavid du Colombier static int
satawait(uchar * p,uchar mask,uchar v,int ms)4424de34a7eSDavid du Colombier satawait(uchar *p, uchar mask, uchar v, int ms)
4434de34a7eSDavid du Colombier {
4444de34a7eSDavid du Colombier int i;
4454de34a7eSDavid du Colombier
44657195852SDavid du Colombier for(i=0; i<ms && (*p & mask) != v; i++)
4474de34a7eSDavid du Colombier microdelay(1000);
4484de34a7eSDavid du Colombier return (*p & mask) == v;
4494de34a7eSDavid du Colombier }
4504de34a7eSDavid du Colombier
4514de34a7eSDavid du Colombier /*
4524de34a7eSDavid du Colombier * Drive initialization
4534de34a7eSDavid du Colombier */
45441dd6b47SDavid du Colombier /* unmask in the pci registers err done */
45557195852SDavid du Colombier static void
unmask(ulong * mmio,int port,int coal)45657195852SDavid du Colombier unmask(ulong *mmio, int port, int coal)
45757195852SDavid du Colombier {
45857195852SDavid du Colombier port &= 7;
45957195852SDavid du Colombier if(coal)
46057195852SDavid du Colombier coal = 1;
46157195852SDavid du Colombier if (port < 4)
46257195852SDavid du Colombier mmio[0x1d64/4] |= (3 << (((port&3)*2)) | (coal<<8));
46357195852SDavid du Colombier else
46457195852SDavid du Colombier mmio[0x1d64/4] |= (3 << (((port&3)*2+9)) | (coal<<17));
46557195852SDavid du Colombier }
46657195852SDavid du Colombier
46757195852SDavid du Colombier static void
mask(ulong * mmio,int port,int coal)46857195852SDavid du Colombier mask(ulong *mmio, int port, int coal)
46957195852SDavid du Colombier {
47057195852SDavid du Colombier port &= 7;
47157195852SDavid du Colombier if(coal)
47257195852SDavid du Colombier coal = 1;
47357195852SDavid du Colombier if (port < 4)
47457195852SDavid du Colombier mmio[0x1d64/4] &= ~(3 << (((port&3)*2)) | (coal<<8));
47557195852SDavid du Colombier else
47657195852SDavid du Colombier mmio[0x1d64/4] &= ~(3 << (((port&3)*2+9)) | (coal<<17));
47757195852SDavid du Colombier }
47857195852SDavid du Colombier
47957195852SDavid du Colombier /* I give up, marvell. You win. */
48057195852SDavid du Colombier static void
phyerrata(Drive * d)48157195852SDavid du Colombier phyerrata(Drive *d)
48257195852SDavid du Colombier {
48357195852SDavid du Colombier ulong n, m;
48457195852SDavid du Colombier enum { BadAutoCal = 0xf << 26, };
48557195852SDavid du Colombier
48657195852SDavid du Colombier if (d->ctlr->type == 1)
48757195852SDavid du Colombier return;
48857195852SDavid du Colombier microdelay(200);
48957195852SDavid du Colombier n = d->bridge->phymode2;
49057195852SDavid du Colombier while ((n & BadAutoCal) == BadAutoCal) {
49157195852SDavid du Colombier dprint("%s: badautocal\n", d->unit->name);
49257195852SDavid du Colombier n &= ~(1<<16);
49357195852SDavid du Colombier n |= (1<<31);
49457195852SDavid du Colombier d->bridge->phymode2 = n;
49557195852SDavid du Colombier microdelay(200);
49657195852SDavid du Colombier d->bridge->phymode2 &= ~((1<<16) | (1<<31));
49757195852SDavid du Colombier microdelay(200);
49857195852SDavid du Colombier n = d->bridge->phymode2;
49957195852SDavid du Colombier }
50057195852SDavid du Colombier n &= ~(1<<31);
50157195852SDavid du Colombier d->bridge->phymode2 = n;
50257195852SDavid du Colombier microdelay(200);
50357195852SDavid du Colombier
50457195852SDavid du Colombier /* abra cadabra! (random magic) */
50557195852SDavid du Colombier m = d->bridge->phymode3;
50657195852SDavid du Colombier m &= ~0x7f800000;
50757195852SDavid du Colombier m |= 0x2a800000;
50857195852SDavid du Colombier d->bridge->phymode3 = m;
50957195852SDavid du Colombier
51057195852SDavid du Colombier /* fix phy mode 4 */
51157195852SDavid du Colombier m = d->bridge->phymode3;
51257195852SDavid du Colombier n = d->bridge->phymode4;
51357195852SDavid du Colombier n &= ~(1<<1);
51457195852SDavid du Colombier n |= 1;
51557195852SDavid du Colombier switch(d->ctlr->rid){
51657195852SDavid du Colombier case REV60X1B2:
51757195852SDavid du Colombier default:
51857195852SDavid du Colombier d->bridge->phymode4 = n;
51957195852SDavid du Colombier d->bridge->phymode3 = m;
52057195852SDavid du Colombier break;
52157195852SDavid du Colombier case REV60X1C0:
52257195852SDavid du Colombier d->bridge->phymode4 = n;
52357195852SDavid du Colombier break;
52457195852SDavid du Colombier }
52557195852SDavid du Colombier
52657195852SDavid du Colombier /* revert values of pre-emphasis and signal amps to the saved ones */
52757195852SDavid du Colombier n = d->bridge->phymode2;
52857195852SDavid du Colombier n &= ~Mpreamp;
52957195852SDavid du Colombier n |= d->pm2;
53057195852SDavid du Colombier n &= ~(1<<16);
53157195852SDavid du Colombier d->bridge->phymode2 = n;
53257195852SDavid du Colombier }
53357195852SDavid du Colombier
53457195852SDavid du Colombier static void
edmacleanout(Drive * d)53557195852SDavid du Colombier edmacleanout(Drive *d)
5364de34a7eSDavid du Colombier {
5374de34a7eSDavid du Colombier int i;
53857195852SDavid du Colombier Srb *srb;
5394de34a7eSDavid du Colombier
54057195852SDavid du Colombier for(i=0; i<nelem(d->srb); i++){
54157195852SDavid du Colombier if(srb = d->srb[i]){
54257195852SDavid du Colombier d->srb[i] = nil;
54357195852SDavid du Colombier d->nsrb--;
54457195852SDavid du Colombier srb->flag |= SFerror|SFdone;
54557195852SDavid du Colombier wakeup(srb);
5464de34a7eSDavid du Colombier }
54757195852SDavid du Colombier }
54857195852SDavid du Colombier while(srb = d->srbhead){
54957195852SDavid du Colombier d->srbhead = srb->next;
55057195852SDavid du Colombier srb->flag |= SFerror|SFdone;
55157195852SDavid du Colombier wakeup(srb);
55257195852SDavid du Colombier }
55357195852SDavid du Colombier }
55457195852SDavid du Colombier
55557195852SDavid du Colombier static void
resetdisk(Drive * d)55657195852SDavid du Colombier resetdisk(Drive *d)
55757195852SDavid du Colombier {
55857195852SDavid du Colombier ulong n;
55957195852SDavid du Colombier
56057195852SDavid du Colombier d->sectors = 0;
56157195852SDavid du Colombier d->unit->sectors = 0;
56257195852SDavid du Colombier if (d->ctlr->type == 2) {
56341dd6b47SDavid du Colombier /*
56441dd6b47SDavid du Colombier * without bit 8 we can boot without disks, but
56541dd6b47SDavid du Colombier * inserted disks will never appear. :-X
56641dd6b47SDavid du Colombier */
56757195852SDavid du Colombier n = d->edma->sataconfig;
56857195852SDavid du Colombier n &= 0xff;
56957195852SDavid du Colombier n |= 0x9b1100;
57057195852SDavid du Colombier d->edma->sataconfig = n;
57141dd6b47SDavid du Colombier n = d->edma->sataconfig; /* flush */
57257195852SDavid du Colombier USED(n);
57357195852SDavid du Colombier }
57457195852SDavid du Colombier d->edma->ctl = eDsEDMA;
57557195852SDavid du Colombier microdelay(1);
57657195852SDavid du Colombier d->edma->ctl = eAtaRst;
57757195852SDavid du Colombier microdelay(25);
57857195852SDavid du Colombier d->edma->ctl = 0;
57957195852SDavid du Colombier if (satawait((uchar *)&d->edma->ctl, eEnEDMA, 0, 3*1000) == 0)
58057195852SDavid du Colombier print("%s: eEnEDMA never cleared on reset\n", d->unit->name);
58157195852SDavid du Colombier edmacleanout(d);
58257195852SDavid du Colombier phyerrata(d);
58357195852SDavid du Colombier d->bridge->sctrl = 0x301 | (d->mode << 4);
58457195852SDavid du Colombier d->state = Dmissing;
58557195852SDavid du Colombier }
58657195852SDavid du Colombier
58757195852SDavid du Colombier static void
edmainit(Drive * d)58857195852SDavid du Colombier edmainit(Drive *d)
58957195852SDavid du Colombier {
59057195852SDavid du Colombier int i;
59157195852SDavid du Colombier
59257195852SDavid du Colombier if(d->tx != nil)
59357195852SDavid du Colombier return;
59457195852SDavid du Colombier
59557195852SDavid du Colombier d->tx = xspanalloc(32*sizeof(Tx), 1024, 0);
59657195852SDavid du Colombier d->rx = xspanalloc(32*sizeof(Rx), 256, 0);
59757195852SDavid du Colombier d->prd = xspanalloc(32*sizeof(Prd), 32, 0);
5984de34a7eSDavid du Colombier for(i = 0; i < 32; i++)
5994de34a7eSDavid du Colombier d->tx[i].prdpa = PADDR(&d->prd[i]);
6004de34a7eSDavid du Colombier coherence();
6014de34a7eSDavid du Colombier }
6024de34a7eSDavid du Colombier
60357195852SDavid du Colombier static int
configdrive(Ctlr * ctlr,Drive * d,SDunit * unit)60457195852SDavid du Colombier configdrive(Ctlr *ctlr, Drive *d, SDunit *unit)
60557195852SDavid du Colombier {
60657195852SDavid du Colombier dprint("%s: configdrive\n", unit->name);
60757195852SDavid du Colombier if(d->driveno < 0)
60857195852SDavid du Colombier panic("mv50xx: configdrive: unset driveno\n");
60957195852SDavid du Colombier d->unit = unit;
61057195852SDavid du Colombier edmainit(d);
61157195852SDavid du Colombier d->mode = DMsatai;
61257195852SDavid du Colombier if(d->ctlr->type == 1){
61357195852SDavid du Colombier d->edma->iem = IEM;
61457195852SDavid du Colombier d->bridge = &d->chip->arb->bridge[d->chipx];
61557195852SDavid du Colombier }else{
61657195852SDavid du Colombier d->edma->iem = IEM2;
61757195852SDavid du Colombier d->bridge = &d->chip->edma[d->chipx].port;
61857195852SDavid du Colombier d->edma->iem = ~(1<<6);
61957195852SDavid du Colombier d->pm2 = Dpreamp;
62057195852SDavid du Colombier if(d->ctlr->lmmio[0x180d8/4] & 1)
62157195852SDavid du Colombier d->pm2 = d->bridge->phymode2 & Mpreamp;
62257195852SDavid du Colombier }
62357195852SDavid du Colombier resetdisk(d);
62457195852SDavid du Colombier unmask(ctlr->lmmio, d->driveno, 0);
62557195852SDavid du Colombier delay(100);
62657195852SDavid du Colombier if(d->bridge->status){
62757195852SDavid du Colombier dprint("%s: configdrive: found drive %lx\n", unit->name, d->bridge->status);
62857195852SDavid du Colombier return 0;
62957195852SDavid du Colombier }
63057195852SDavid du Colombier return -1;
6314de34a7eSDavid du Colombier }
6324de34a7eSDavid du Colombier
6334de34a7eSDavid du Colombier static int
enabledrive(Drive * d)6344de34a7eSDavid du Colombier enabledrive(Drive *d)
6354de34a7eSDavid du Colombier {
6364de34a7eSDavid du Colombier Edma *edma;
6374de34a7eSDavid du Colombier
63857195852SDavid du Colombier dprint("%s: enabledrive..", d->unit->name);
6394de34a7eSDavid du Colombier
64057195852SDavid du Colombier if((d->bridge->status & 0xf) != 3){
64157195852SDavid du Colombier dprint("%s: not present\n", d->unit->name);
6424de34a7eSDavid du Colombier d->state = Dmissing;
64357195852SDavid du Colombier return -1;
6444de34a7eSDavid du Colombier }
6454de34a7eSDavid du Colombier edma = d->edma;
64657195852SDavid du Colombier if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){
64757195852SDavid du Colombier dprint("%s: busy timeout\n", d->unit->name);
6484de34a7eSDavid du Colombier d->state = Dmissing;
64957195852SDavid du Colombier return -1;
6504de34a7eSDavid du Colombier }
6514de34a7eSDavid du Colombier edma->iec = 0;
6524de34a7eSDavid du Colombier d->chip->arb->ic &= ~(0x101 << d->chipx);
65357195852SDavid du Colombier edma->config = 0x51f;
65457195852SDavid du Colombier if (d->ctlr->type == 2)
65557195852SDavid du Colombier edma->config |= 7<<11;
6564de34a7eSDavid du Colombier edma->txi = PADDR(d->tx);
65757195852SDavid du Colombier edma->txo = (ulong)d->tx & 0x3e0;
65857195852SDavid du Colombier edma->rxi = (ulong)d->rx & 0xf8;
6594de34a7eSDavid du Colombier edma->rxo = PADDR(d->rx);
6604de34a7eSDavid du Colombier edma->ctl |= 1; /* enable dma */
6614de34a7eSDavid du Colombier
66257195852SDavid du Colombier if(d->bridge->status = 0x113){
66357195852SDavid du Colombier dprint("%s: new\n", d->unit->name);
6644de34a7eSDavid du Colombier d->state = Dnew;
66557195852SDavid du Colombier }else
66657195852SDavid du Colombier print("%s: status not forced (should be okay)\n", d->unit->name);
66757195852SDavid du Colombier return 0;
6684de34a7eSDavid du Colombier }
6694de34a7eSDavid du Colombier
6704de34a7eSDavid du Colombier static void
disabledrive(Drive * d)6714de34a7eSDavid du Colombier disabledrive(Drive *d)
6724de34a7eSDavid du Colombier {
6734de34a7eSDavid du Colombier int i;
6744de34a7eSDavid du Colombier ulong *r;
6754de34a7eSDavid du Colombier
67657195852SDavid du Colombier dprint("%s: disabledrive\n", d->unit->name);
6774de34a7eSDavid du Colombier
6784de34a7eSDavid du Colombier if(d->tx == nil) /* never enabled */
6794de34a7eSDavid du Colombier return;
6804de34a7eSDavid du Colombier
6814de34a7eSDavid du Colombier d->edma->ctl = 0;
6824de34a7eSDavid du Colombier d->edma->iem = 0;
6834de34a7eSDavid du Colombier
68457195852SDavid du Colombier r = (ulong*)(d->ctlr->mmio + 0x1d64);
6854de34a7eSDavid du Colombier i = d->chipx;
6864de34a7eSDavid du Colombier if(d->chipx < 4)
6874de34a7eSDavid du Colombier *r &= ~(3 << (i*2));
6884de34a7eSDavid du Colombier else
6894de34a7eSDavid du Colombier *r |= ~(3 << (i*2+9));
6904de34a7eSDavid du Colombier }
6914de34a7eSDavid du Colombier
6924de34a7eSDavid du Colombier static int
setudmamode(Drive * d,uchar mode)6934de34a7eSDavid du Colombier setudmamode(Drive *d, uchar mode)
6944de34a7eSDavid du Colombier {
6954de34a7eSDavid du Colombier Edma *edma;
6964de34a7eSDavid du Colombier
69757195852SDavid du Colombier dprint("%s: setudmamode %d\n", d->unit->name, mode);
6984de34a7eSDavid du Colombier
6994de34a7eSDavid du Colombier edma = d->edma;
70057195852SDavid du Colombier if (edma == nil) {
70157195852SDavid du Colombier iprint("setudamode(m%d): zero d->edma\m", d->driveno);
70257195852SDavid du Colombier return 0;
70357195852SDavid du Colombier }
70457195852SDavid du Colombier if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 9*1000) == 0){
70557195852SDavid du Colombier iprint("%s: cmdstat 0x%.2ux ready timeout\n", d->unit->name, edma->cmdstat);
7064de34a7eSDavid du Colombier return 0;
7074de34a7eSDavid du Colombier }
7084de34a7eSDavid du Colombier edma->altstat = ATAeIEN;
7094de34a7eSDavid du Colombier edma->err = 3;
7104de34a7eSDavid du Colombier edma->seccnt = 0x40 | mode;
71157195852SDavid du Colombier edma->cmdstat = 0xef;
7124de34a7eSDavid du Colombier microdelay(1);
71357195852SDavid du Colombier if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0){
71457195852SDavid du Colombier iprint("%s: cmdstat 0x%.2ux busy timeout\n", d->unit->name, edma->cmdstat);
7154de34a7eSDavid du Colombier return 0;
7164de34a7eSDavid du Colombier }
7174de34a7eSDavid du Colombier return 1;
7184de34a7eSDavid du Colombier }
7194de34a7eSDavid du Colombier
72057195852SDavid du Colombier static int
identifydrive(Drive * d)7214de34a7eSDavid du Colombier identifydrive(Drive *d)
7224de34a7eSDavid du Colombier {
7234de34a7eSDavid du Colombier int i;
7244de34a7eSDavid du Colombier ushort *id;
7254de34a7eSDavid du Colombier Edma *edma;
7264de34a7eSDavid du Colombier SDunit *unit;
7274de34a7eSDavid du Colombier
72857195852SDavid du Colombier dprint("%s: identifydrive\n", d->unit->name);
7294de34a7eSDavid du Colombier
7304de34a7eSDavid du Colombier if(setudmamode(d, 5) == 0) /* do all SATA support 5? */
7314de34a7eSDavid du Colombier goto Error;
7324de34a7eSDavid du Colombier
7334de34a7eSDavid du Colombier id = d->info;
7344de34a7eSDavid du Colombier memset(d->info, 0, sizeof d->info);
7354de34a7eSDavid du Colombier edma = d->edma;
73657195852SDavid du Colombier if(satawait(&edma->cmdstat, ~ATAobs, ATAdrdy, 5*1000) == 0)
7374de34a7eSDavid du Colombier goto Error;
7384de34a7eSDavid du Colombier
7394de34a7eSDavid du Colombier edma->altstat = ATAeIEN; /* no interrupts */
74057195852SDavid du Colombier edma->cmdstat = 0xec;
7414de34a7eSDavid du Colombier microdelay(1);
74257195852SDavid du Colombier if(satawait(&edma->cmdstat, ATAbusy, 0, 5*1000) == 0)
7434de34a7eSDavid du Colombier goto Error;
7444de34a7eSDavid du Colombier for(i = 0; i < 256; i++)
7454de34a7eSDavid du Colombier id[i] = edma->pio;
74657195852SDavid du Colombier if(edma->cmdstat & ATAbad)
7474de34a7eSDavid du Colombier goto Error;
7484de34a7eSDavid du Colombier i = lhgets(id+83) | lhgets(id+86);
7494de34a7eSDavid du Colombier if(i & (1<<10)){
7504de34a7eSDavid du Colombier d->flag |= Dext;
7514de34a7eSDavid du Colombier d->sectors = lhgetv(id+100);
7524de34a7eSDavid du Colombier }else{
7534de34a7eSDavid du Colombier d->flag &= ~Dext;
7544de34a7eSDavid du Colombier d->sectors = lhgetl(id+60);
7554de34a7eSDavid du Colombier }
7564de34a7eSDavid du Colombier idmove(d->serial, id+10, 20);
7574de34a7eSDavid du Colombier idmove(d->firmware, id+23, 8);
7584de34a7eSDavid du Colombier idmove(d->model, id+27, 40);
7594de34a7eSDavid du Colombier
7604de34a7eSDavid du Colombier unit = d->unit;
7614de34a7eSDavid du Colombier memset(unit->inquiry, 0, sizeof unit->inquiry);
7624de34a7eSDavid du Colombier unit->inquiry[2] = 2;
7634de34a7eSDavid du Colombier unit->inquiry[3] = 2;
7644de34a7eSDavid du Colombier unit->inquiry[4] = sizeof(unit->inquiry)-4;
7654de34a7eSDavid du Colombier idmove((char*)unit->inquiry+8, id+27, 40);
7664de34a7eSDavid du Colombier
76757195852SDavid du Colombier if(enabledrive(d) == 0) {
7684de34a7eSDavid du Colombier d->state = Dready;
76957195852SDavid du Colombier d->mediachange = 1;
77057195852SDavid du Colombier idprint("%s: LLBA %lld sectors\n", d->unit->name, d->sectors);
77157195852SDavid du Colombier } else
7724de34a7eSDavid du Colombier d->state = Derror;
77357195852SDavid du Colombier if(d->state == Dready)
77457195852SDavid du Colombier return 0;
77557195852SDavid du Colombier return -1;
7764de34a7eSDavid du Colombier Error:
77757195852SDavid du Colombier dprint("error...");
7784de34a7eSDavid du Colombier d->state = Derror;
77957195852SDavid du Colombier return -1;
7804de34a7eSDavid du Colombier }
7814de34a7eSDavid du Colombier
78257195852SDavid du Colombier /* p. 163:
78357195852SDavid du Colombier M recovered error
78457195852SDavid du Colombier P protocol error
78557195852SDavid du Colombier N PhyRdy change
78657195852SDavid du Colombier W CommWake
78757195852SDavid du Colombier B 8-to-10 encoding error
78857195852SDavid du Colombier D disparity error
78957195852SDavid du Colombier C crc error
79057195852SDavid du Colombier H handshake error
79157195852SDavid du Colombier S link sequence error
79257195852SDavid du Colombier T transport state transition error
79357195852SDavid du Colombier F unrecognized fis type
79457195852SDavid du Colombier X device changed
79557195852SDavid du Colombier */
79657195852SDavid du Colombier
79757195852SDavid du Colombier static char stab[] = {
79857195852SDavid du Colombier [1] 'M',
79957195852SDavid du Colombier [10] 'P',
80057195852SDavid du Colombier [16] 'N',
80157195852SDavid du Colombier [18] 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
80257195852SDavid du Colombier };
80357195852SDavid du Colombier static ulong sbad = (7<<20)|(3<<23);
8044de34a7eSDavid du Colombier
8054de34a7eSDavid du Colombier static void
serrdecode(ulong r,char * s,char * e)80657195852SDavid du Colombier serrdecode(ulong r, char *s, char *e)
80757195852SDavid du Colombier {
80857195852SDavid du Colombier int i;
80957195852SDavid du Colombier
81057195852SDavid du Colombier e -= 3;
81157195852SDavid du Colombier for(i = 0; i < nelem(stab) && s < e; i++){
81257195852SDavid du Colombier if((r&(1<<i)) && stab[i]){
81357195852SDavid du Colombier *s++ = stab[i];
81457195852SDavid du Colombier if(sbad&(1<<i))
81557195852SDavid du Colombier *s++ = '*';
81657195852SDavid du Colombier }
81757195852SDavid du Colombier }
81857195852SDavid du Colombier *s = 0;
81957195852SDavid du Colombier }
82057195852SDavid du Colombier
82157195852SDavid du Colombier char *iectab[] = {
82257195852SDavid du Colombier "ePrtDataErr",
82357195852SDavid du Colombier "ePrtPRDErr",
82457195852SDavid du Colombier "eDevErr",
82557195852SDavid du Colombier "eDevDis",
82657195852SDavid du Colombier "eDevCon",
82757195852SDavid du Colombier "SerrInt",
82857195852SDavid du Colombier "eUnderrun",
82957195852SDavid du Colombier "eSelfDis2",
83057195852SDavid du Colombier "eSelfDis",
83157195852SDavid du Colombier "ePrtCRQBErr",
83257195852SDavid du Colombier "ePrtCRPBErr",
83357195852SDavid du Colombier "ePrtIntErr",
83457195852SDavid du Colombier "eIORdyErr",
83557195852SDavid du Colombier };
83657195852SDavid du Colombier
83757195852SDavid du Colombier static char*
iecdecode(ulong cause)83857195852SDavid du Colombier iecdecode(ulong cause)
83957195852SDavid du Colombier {
84057195852SDavid du Colombier int i;
84157195852SDavid du Colombier
84257195852SDavid du Colombier for(i = 0; i < nelem(iectab); i++)
84357195852SDavid du Colombier if(cause&(1<<i))
84457195852SDavid du Colombier return iectab[i];
84557195852SDavid du Colombier return "";
84657195852SDavid du Colombier }
84757195852SDavid du Colombier
84857195852SDavid du Colombier enum{
84957195852SDavid du Colombier Cerror = ePrtDataErr|ePrtPRDErr|eDevErr|eSelfDis2|ePrtCRPBErr|ePrtIntErr,
85057195852SDavid du Colombier };
85157195852SDavid du Colombier
85257195852SDavid du Colombier static void
updatedrive(Drive * d)85357195852SDavid du Colombier updatedrive(Drive *d)
8544de34a7eSDavid du Colombier {
8554de34a7eSDavid du Colombier int x;
85657195852SDavid du Colombier ulong cause;
8574de34a7eSDavid du Colombier Edma *edma;
85857195852SDavid du Colombier char buf[32+4+1];
8594de34a7eSDavid du Colombier
8604de34a7eSDavid du Colombier edma = d->edma;
86157195852SDavid du Colombier if((edma->ctl&eEnEDMA) == 0){
86241dd6b47SDavid du Colombier /* FEr SATA#4 40xx */
86357195852SDavid du Colombier x = d->edma->cmdstat;
86457195852SDavid du Colombier USED(x);
8654de34a7eSDavid du Colombier }
86657195852SDavid du Colombier cause = edma->iec;
86757195852SDavid du Colombier if(cause == 0)
86857195852SDavid du Colombier return;
86957195852SDavid du Colombier dprint("%s: cause %08ulx [%s]\n", d->unit->name, cause, iecdecode(cause));
87057195852SDavid du Colombier if(cause & eDevCon)
8714de34a7eSDavid du Colombier d->state = Dnew;
87257195852SDavid du Colombier if(cause&eDevDis && d->state == Dready)
87357195852SDavid du Colombier iprint("%s: pulled: st=%08ulx\n", d->unit->name, cause);
87457195852SDavid du Colombier switch(d->ctlr->type){
87557195852SDavid du Colombier case 1:
8764de34a7eSDavid du Colombier if(cause&eSelfDis)
8774de34a7eSDavid du Colombier d->state = Derror;
87857195852SDavid du Colombier break;
87957195852SDavid du Colombier case 2:
88057195852SDavid du Colombier if(cause&Cerror)
88157195852SDavid du Colombier d->state = Derror;
88257195852SDavid du Colombier if(cause&SerrInt){
88357195852SDavid du Colombier serrdecode(d->bridge->serror, buf, buf+sizeof buf);
88457195852SDavid du Colombier dprint("%s: serror %08ulx [%s]\n", d->unit->name, (ulong)d->bridge->serror, buf);
88557195852SDavid du Colombier d->bridge->serror = d->bridge->serror;
88657195852SDavid du Colombier }
88757195852SDavid du Colombier }
88857195852SDavid du Colombier edma->iec = ~cause;
8894de34a7eSDavid du Colombier }
8904de34a7eSDavid du Colombier
8914de34a7eSDavid du Colombier /*
8924de34a7eSDavid du Colombier * Requests
8934de34a7eSDavid du Colombier */
8944de34a7eSDavid du Colombier static Srb*
srbrw(int req,Drive * d,uchar * data,uint sectors,uvlong lba)8954de34a7eSDavid du Colombier srbrw(int req, Drive *d, uchar *data, uint sectors, uvlong lba)
8964de34a7eSDavid du Colombier {
8974de34a7eSDavid du Colombier int i;
8984de34a7eSDavid du Colombier Srb *srb;
8994de34a7eSDavid du Colombier static uchar cmd[2][2] = { 0xC8, 0x25, 0xCA, 0x35 };
9004de34a7eSDavid du Colombier
9014de34a7eSDavid du Colombier srb = allocsrb();
9024de34a7eSDavid du Colombier srb->req = req;
9034de34a7eSDavid du Colombier srb->drive = d;
9044de34a7eSDavid du Colombier srb->blockno = lba;
9054de34a7eSDavid du Colombier srb->sectors = sectors;
9064de34a7eSDavid du Colombier srb->count = sectors*512;
9074de34a7eSDavid du Colombier srb->flag = 0;
9084de34a7eSDavid du Colombier srb->data = data;
9094de34a7eSDavid du Colombier
9104de34a7eSDavid du Colombier for(i=0; i<6; i++)
9114de34a7eSDavid du Colombier srb->lba[i] = lba >> (8*i);
9124de34a7eSDavid du Colombier srb->cmd = cmd[srb->req!=SRBread][(d->flag&Dext)!=0];
9134de34a7eSDavid du Colombier return srb;
9144de34a7eSDavid du Colombier }
9154de34a7eSDavid du Colombier
9164de34a7eSDavid du Colombier static uintptr
advance(uintptr pa,int shift)9174de34a7eSDavid du Colombier advance(uintptr pa, int shift)
9184de34a7eSDavid du Colombier {
9194de34a7eSDavid du Colombier int n, mask;
9204de34a7eSDavid du Colombier
9214de34a7eSDavid du Colombier mask = 0x1F<<shift;
9224de34a7eSDavid du Colombier n = (pa & mask) + (1<<shift);
9234de34a7eSDavid du Colombier return (pa & ~mask) | (n & mask);
9244de34a7eSDavid du Colombier }
9254de34a7eSDavid du Colombier
9264de34a7eSDavid du Colombier #define CMD(r, v) (((r)<<8) | ((v)&0xFF))
9274de34a7eSDavid du Colombier static void
mvsatarequest(ushort * cmd,Srb * srb,int ext)92857195852SDavid du Colombier mvsatarequest(ushort *cmd, Srb *srb, int ext)
9294de34a7eSDavid du Colombier {
9304de34a7eSDavid du Colombier *cmd++ = CMD(ARseccnt, 0);
9314de34a7eSDavid du Colombier *cmd++ = CMD(ARseccnt, srb->sectors);
9324de34a7eSDavid du Colombier *cmd++ = CMD(ARfea, 0);
9334de34a7eSDavid du Colombier if(ext){
9344de34a7eSDavid du Colombier *cmd++ = CMD(ARlba0, srb->lba[3]);
9354de34a7eSDavid du Colombier *cmd++ = CMD(ARlba0, srb->lba[0]);
9364de34a7eSDavid du Colombier *cmd++ = CMD(ARlba1, srb->lba[4]);
9374de34a7eSDavid du Colombier *cmd++ = CMD(ARlba1, srb->lba[1]);
9384de34a7eSDavid du Colombier *cmd++ = CMD(ARlba2, srb->lba[5]);
9394de34a7eSDavid du Colombier *cmd++ = CMD(ARlba2, srb->lba[2]);
94057195852SDavid du Colombier *cmd++ = CMD(ARdev, 0xe0);
9414de34a7eSDavid du Colombier }else{
9424de34a7eSDavid du Colombier *cmd++ = CMD(ARlba0, srb->lba[0]);
9434de34a7eSDavid du Colombier *cmd++ = CMD(ARlba1, srb->lba[1]);
9444de34a7eSDavid du Colombier *cmd++ = CMD(ARlba2, srb->lba[2]);
94557195852SDavid du Colombier *cmd++ = CMD(ARdev, srb->lba[3] | 0xe0);
9464de34a7eSDavid du Colombier }
94757195852SDavid du Colombier *cmd = CMD(ARcmd, srb->cmd) | (1<<15);
9484de34a7eSDavid du Colombier }
9494de34a7eSDavid du Colombier
9504de34a7eSDavid du Colombier static void
startsrb(Drive * d,Srb * srb)9514de34a7eSDavid du Colombier startsrb(Drive *d, Srb *srb)
9524de34a7eSDavid du Colombier {
9534de34a7eSDavid du Colombier int i;
9544de34a7eSDavid du Colombier Edma *edma;
9554de34a7eSDavid du Colombier Prd *prd;
9564de34a7eSDavid du Colombier Tx *tx;
9574de34a7eSDavid du Colombier
9584de34a7eSDavid du Colombier if(d->nsrb >= nelem(d->srb)){
9594de34a7eSDavid du Colombier srb->next = nil;
9604de34a7eSDavid du Colombier if(d->srbhead)
9614de34a7eSDavid du Colombier d->srbtail->next = srb;
9624de34a7eSDavid du Colombier else
9634de34a7eSDavid du Colombier d->srbhead = srb;
9644de34a7eSDavid du Colombier d->srbtail = srb;
9654de34a7eSDavid du Colombier return;
9664de34a7eSDavid du Colombier }
9674de34a7eSDavid du Colombier
9684de34a7eSDavid du Colombier d->nsrb++;
9694de34a7eSDavid du Colombier for(i=0; i<nelem(d->srb); i++)
9704de34a7eSDavid du Colombier if(d->srb[i] == nil)
9714de34a7eSDavid du Colombier break;
9724de34a7eSDavid du Colombier if(i == nelem(d->srb))
9734de34a7eSDavid du Colombier panic("sdmv50xx: no free srbs");
97457195852SDavid du Colombier d->intick = MACHP(0)->ticks;
9754de34a7eSDavid du Colombier d->srb[i] = srb;
9764de34a7eSDavid du Colombier edma = d->edma;
9774de34a7eSDavid du Colombier tx = (Tx*)KADDR(edma->txi);
9784de34a7eSDavid du Colombier tx->flag = (i<<1) | (srb->req == SRBread);
9794de34a7eSDavid du Colombier prd = KADDR(tx->prdpa);
9804de34a7eSDavid du Colombier prd->pa = PADDR(srb->data);
9814de34a7eSDavid du Colombier prd->count = srb->count;
9824de34a7eSDavid du Colombier prd->flag = PRDeot;
98357195852SDavid du Colombier mvsatarequest(tx->regs, srb, d->flag&Dext);
9844de34a7eSDavid du Colombier coherence();
9854de34a7eSDavid du Colombier edma->txi = advance(edma->txi, 5);
98657195852SDavid du Colombier d->intick = MACHP(0)->ticks;
9874de34a7eSDavid du Colombier }
9884de34a7eSDavid du Colombier
98957195852SDavid du Colombier enum{
99057195852SDavid du Colombier Rpidx = 0x1f<<3,
99157195852SDavid du Colombier };
99257195852SDavid du Colombier
9934de34a7eSDavid du Colombier static void
completesrb(Drive * d)9944de34a7eSDavid du Colombier completesrb(Drive *d)
9954de34a7eSDavid du Colombier {
9964de34a7eSDavid du Colombier Edma *edma;
9974de34a7eSDavid du Colombier Rx *rx;
9984de34a7eSDavid du Colombier Srb *srb;
9994de34a7eSDavid du Colombier
10004de34a7eSDavid du Colombier edma = d->edma;
10014de34a7eSDavid du Colombier if((edma->ctl & eEnEDMA) == 0)
10024de34a7eSDavid du Colombier return;
10034de34a7eSDavid du Colombier
100457195852SDavid du Colombier while((edma->rxo&Rpidx) != (edma->rxi&Rpidx)){
10054de34a7eSDavid du Colombier rx = (Rx*)KADDR(edma->rxo);
10064de34a7eSDavid du Colombier if(srb = d->srb[rx->cid]){
10074de34a7eSDavid du Colombier d->srb[rx->cid] = nil;
10084de34a7eSDavid du Colombier d->nsrb--;
100957195852SDavid du Colombier if(rx->cDevSts & ATAbad)
10104de34a7eSDavid du Colombier srb->flag |= SFerror;
101157195852SDavid du Colombier if (rx->cEdmaSts)
101257195852SDavid du Colombier iprint("cEdmaSts: %02ux\n", rx->cEdmaSts);
10134de34a7eSDavid du Colombier srb->sta = rx->cDevSts;
101457195852SDavid du Colombier srb->flag |= SFdone;
10154de34a7eSDavid du Colombier wakeup(srb);
10164de34a7eSDavid du Colombier }else
10174de34a7eSDavid du Colombier iprint("srb missing\n");
10184de34a7eSDavid du Colombier edma->rxo = advance(edma->rxo, 3);
10194de34a7eSDavid du Colombier if(srb = d->srbhead){
10204de34a7eSDavid du Colombier d->srbhead = srb->next;
10214de34a7eSDavid du Colombier startsrb(d, srb);
10224de34a7eSDavid du Colombier }
10234de34a7eSDavid du Colombier }
10244de34a7eSDavid du Colombier }
10254de34a7eSDavid du Colombier
10264de34a7eSDavid du Colombier static int
srbdone(void * v)10274de34a7eSDavid du Colombier srbdone(void *v)
10284de34a7eSDavid du Colombier {
10294de34a7eSDavid du Colombier Srb *srb;
10304de34a7eSDavid du Colombier
10314de34a7eSDavid du Colombier srb = v;
10324de34a7eSDavid du Colombier return srb->flag & SFdone;
10334de34a7eSDavid du Colombier }
10344de34a7eSDavid du Colombier
10354de34a7eSDavid du Colombier /*
10364de34a7eSDavid du Colombier * Interrupts
10374de34a7eSDavid du Colombier */
10384de34a7eSDavid du Colombier static void
mv50interrupt(Ureg *,void * a)10394de34a7eSDavid du Colombier mv50interrupt(Ureg*, void *a)
10404de34a7eSDavid du Colombier {
10414de34a7eSDavid du Colombier int i;
10424de34a7eSDavid du Colombier ulong cause;
10434de34a7eSDavid du Colombier Ctlr *ctlr;
10444de34a7eSDavid du Colombier Drive *drive;
10454de34a7eSDavid du Colombier
10464de34a7eSDavid du Colombier ctlr = a;
10474de34a7eSDavid du Colombier ilock(ctlr);
104857195852SDavid du Colombier cause = ctlr->lmmio[0x1d60/4];
104957195852SDavid du Colombier // dprint("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause);
105057195852SDavid du Colombier for(i=0; i<ctlr->ndrive; i++)
10514de34a7eSDavid du Colombier if(cause & (3<<(i*2+i/4))){
10524de34a7eSDavid du Colombier drive = &ctlr->drive[i];
105357195852SDavid du Colombier if(drive->edma == 0)
105441dd6b47SDavid du Colombier continue; /* not ready yet. */
10554de34a7eSDavid du Colombier ilock(drive);
105657195852SDavid du Colombier updatedrive(drive);
10574de34a7eSDavid du Colombier while(ctlr->chip[i/4].arb->ic & (0x0101 << (i%4))){
10584de34a7eSDavid du Colombier ctlr->chip[i/4].arb->ic = ~(0x101 << (i%4));
10594de34a7eSDavid du Colombier completesrb(drive);
10604de34a7eSDavid du Colombier }
10614de34a7eSDavid du Colombier iunlock(drive);
10624de34a7eSDavid du Colombier }
10634de34a7eSDavid du Colombier iunlock(ctlr);
10644de34a7eSDavid du Colombier }
10654de34a7eSDavid du Colombier
106657195852SDavid du Colombier enum{
106757195852SDavid du Colombier Nms = 256,
106857195852SDavid du Colombier Midwait = 16*1024/Nms-1,
106957195852SDavid du Colombier Mphywait = 512/Nms-1,
107057195852SDavid du Colombier };
107157195852SDavid du Colombier
107257195852SDavid du Colombier static void
westerndigitalhung(Drive * d)107357195852SDavid du Colombier westerndigitalhung(Drive *d)
107457195852SDavid du Colombier {
107557195852SDavid du Colombier Edma *e;
107657195852SDavid du Colombier
107757195852SDavid du Colombier e = d->edma;
107857195852SDavid du Colombier if(d->srb
107957195852SDavid du Colombier && TK2MS(MACHP(0)->ticks-d->intick) > 5*1000
108057195852SDavid du Colombier && (e->rxo&Rpidx) == (e->rxi&Rpidx)){
108157195852SDavid du Colombier dprint("westerndigital drive hung; resetting\n");
108257195852SDavid du Colombier d->state = Dreset;
108357195852SDavid du Colombier }
108457195852SDavid du Colombier }
108557195852SDavid du Colombier
108657195852SDavid du Colombier static void
checkdrive(Drive * d,int i)108757195852SDavid du Colombier checkdrive(Drive *d, int i)
108857195852SDavid du Colombier {
108957195852SDavid du Colombier static ulong s, olds[NCtlr*NCtlrdrv];
109057195852SDavid du Colombier char *name;
109157195852SDavid du Colombier
109257195852SDavid du Colombier ilock(d);
109357195852SDavid du Colombier name = d->unit->name;
109457195852SDavid du Colombier s = d->bridge->status;
109557195852SDavid du Colombier if(s != olds[i]){
109657195852SDavid du Colombier dprint("%s: status: %08lx -> %08lx: %s\n", name, olds[i], s, diskstates[d->state]);
109757195852SDavid du Colombier olds[i] = s;
109857195852SDavid du Colombier }
109941dd6b47SDavid du Colombier /* westerndigitalhung(d); */
110057195852SDavid du Colombier switch(d->state){
110157195852SDavid du Colombier case Dnew:
110257195852SDavid du Colombier case Dmissing:
110357195852SDavid du Colombier switch(s){
110457195852SDavid du Colombier case 0x000:
110557195852SDavid du Colombier break;
110657195852SDavid du Colombier default:
110757195852SDavid du Colombier dprint("%s: unknown state %8lx\n", name, s);
110857195852SDavid du Colombier case 0x100:
110957195852SDavid du Colombier if(++d->wait&Mphywait)
111057195852SDavid du Colombier break;
111157195852SDavid du Colombier reset: d->mode ^= 1;
111257195852SDavid du Colombier dprint("%s: reset; new mode %d\n", name, d->mode);
111357195852SDavid du Colombier resetdisk(d);
111457195852SDavid du Colombier break;
111557195852SDavid du Colombier case 0x123:
111657195852SDavid du Colombier case 0x113:
111757195852SDavid du Colombier s = d->edma->cmdstat;
111857195852SDavid du Colombier if(s == 0x7f || (s&~ATAobs) != ATAdrdy){
111957195852SDavid du Colombier if((++d->wait&Midwait) == 0)
112057195852SDavid du Colombier goto reset;
112157195852SDavid du Colombier }else if(identifydrive(d) == -1)
112257195852SDavid du Colombier goto reset;
112357195852SDavid du Colombier }
112457195852SDavid du Colombier break;
112557195852SDavid du Colombier case Dready:
112657195852SDavid du Colombier if(s != 0)
112757195852SDavid du Colombier break;
112841dd6b47SDavid du Colombier iprint("%s: pulled: st=%08ulx\n", name, s); /* never happens */
112957195852SDavid du Colombier case Dreset:
113057195852SDavid du Colombier case Derror:
113157195852SDavid du Colombier dprint("%s reset: mode %d\n", name, d->mode);
113257195852SDavid du Colombier resetdisk(d);
113357195852SDavid du Colombier break;
113457195852SDavid du Colombier }
113557195852SDavid du Colombier iunlock(d);
113657195852SDavid du Colombier }
113757195852SDavid du Colombier
113857195852SDavid du Colombier static void
satakproc(void *)113957195852SDavid du Colombier satakproc(void*)
114057195852SDavid du Colombier {
114157195852SDavid du Colombier int i;
114257195852SDavid du Colombier
114357195852SDavid du Colombier while(waserror())
114457195852SDavid du Colombier ;
114557195852SDavid du Colombier
114657195852SDavid du Colombier for(;;){
114757195852SDavid du Colombier tsleep(&up->sleep, return0, 0, Nms);
114857195852SDavid du Colombier for(i = 0; i < nmvsatadrive; i++)
114957195852SDavid du Colombier checkdrive(mvsatadrive[i], i);
115057195852SDavid du Colombier }
115157195852SDavid du Colombier }
115257195852SDavid du Colombier
11534de34a7eSDavid du Colombier /*
11544de34a7eSDavid du Colombier * Device discovery
11554de34a7eSDavid du Colombier */
11564de34a7eSDavid du Colombier static SDev*
mv50pnp(void)11574de34a7eSDavid du Colombier mv50pnp(void)
11584de34a7eSDavid du Colombier {
11594de34a7eSDavid du Colombier int i, nunit;
11604de34a7eSDavid du Colombier uchar *base;
116157195852SDavid du Colombier ulong io, n, *mem;
11624de34a7eSDavid du Colombier Ctlr *ctlr;
11634de34a7eSDavid du Colombier Pcidev *p;
11644de34a7eSDavid du Colombier SDev *head, *tail, *sdev;
116557195852SDavid du Colombier Drive *d;
116657195852SDavid du Colombier static int ctlrno, done;
11674de34a7eSDavid du Colombier
116857195852SDavid du Colombier dprint("mv50pnp\n");
116957195852SDavid du Colombier if(done++)
117057195852SDavid du Colombier return nil;
11714de34a7eSDavid du Colombier
11724de34a7eSDavid du Colombier p = nil;
11734de34a7eSDavid du Colombier head = nil;
11744de34a7eSDavid du Colombier tail = nil;
117557195852SDavid du Colombier while((p = pcimatch(p, 0x11ab, 0)) != nil){
11764de34a7eSDavid du Colombier switch(p->did){
117757195852SDavid du Colombier case 0x5040:
11784de34a7eSDavid du Colombier case 0x5041:
117957195852SDavid du Colombier case 0x5080:
11804de34a7eSDavid du Colombier case 0x5081:
118157195852SDavid du Colombier case 0x6041:
118257195852SDavid du Colombier case 0x6081:
11834de34a7eSDavid du Colombier break;
11844de34a7eSDavid du Colombier default:
118557195852SDavid du Colombier print("mv50pnp: unknown did %ux ignored\n", (ushort)p->did);
11864de34a7eSDavid du Colombier continue;
11874de34a7eSDavid du Colombier }
118857195852SDavid du Colombier if (ctlrno >= NCtlr) {
118957195852SDavid du Colombier print("mv50pnp: too many controllers\n");
119057195852SDavid du Colombier break;
119157195852SDavid du Colombier }
119257195852SDavid du Colombier nunit = (p->did&0xf0) >> 4;
119357195852SDavid du Colombier print("Marvell 88SX%ux: %d SATA-%s ports with%s flash\n",
119457195852SDavid du Colombier (ushort)p->did, nunit,
119557195852SDavid du Colombier ((p->did&0xf000)==0x6000? "II": "I"),
119657195852SDavid du Colombier (p->did&1? "": "out"));
11974de34a7eSDavid du Colombier if((sdev = malloc(sizeof(SDev))) == nil)
11984de34a7eSDavid du Colombier continue;
11994de34a7eSDavid du Colombier if((ctlr = malloc(sizeof(Ctlr))) == nil){
12004de34a7eSDavid du Colombier free(sdev);
12014de34a7eSDavid du Colombier continue;
12024de34a7eSDavid du Colombier }
120357195852SDavid du Colombier memset(sdev, 0, sizeof *sdev);
120457195852SDavid du Colombier memset(ctlr, 0, sizeof *ctlr);
120557195852SDavid du Colombier
12064de34a7eSDavid du Colombier io = p->mem[0].bar & ~0x0F;
120757195852SDavid du Colombier mem = (ulong*)vmap(io, p->mem[0].size);
12084de34a7eSDavid du Colombier if(mem == 0){
12094de34a7eSDavid du Colombier print("sdmv50xx: address 0x%luX in use\n", io);
12104de34a7eSDavid du Colombier free(sdev);
12114de34a7eSDavid du Colombier free(ctlr);
12124de34a7eSDavid du Colombier continue;
12134de34a7eSDavid du Colombier }
121457195852SDavid du Colombier ctlr->rid = p->rid;
121557195852SDavid du Colombier
121641dd6b47SDavid du Colombier /* avert thine eyes! (what does this do?) */
121757195852SDavid du Colombier mem[0x104f0/4] = 0;
121857195852SDavid du Colombier ctlr->type = (p->did >> 12) & 3;
121957195852SDavid du Colombier if(ctlr->type == 1){
122057195852SDavid du Colombier n = mem[0xc00/4];
122157195852SDavid du Colombier n &= ~(3<<4);
122257195852SDavid du Colombier mem[0xc00/4] = n;
122357195852SDavid du Colombier }
122457195852SDavid du Colombier
12254de34a7eSDavid du Colombier sdev->ifc = &sdmv50xxifc;
12264de34a7eSDavid du Colombier sdev->ctlr = ctlr;
12274de34a7eSDavid du Colombier sdev->nunit = nunit;
12284de34a7eSDavid du Colombier sdev->idno = 'E';
12294de34a7eSDavid du Colombier ctlr->sdev = sdev;
12304de34a7eSDavid du Colombier ctlr->irq = p->intl;
12314de34a7eSDavid du Colombier ctlr->tbdf = p->tbdf;
12324de34a7eSDavid du Colombier ctlr->pcidev = p;
123357195852SDavid du Colombier ctlr->lmmio = mem;
123457195852SDavid du Colombier ctlr->mmio = (uchar*)mem;
12354de34a7eSDavid du Colombier ctlr->nchip = (nunit+3)/4;
12364de34a7eSDavid du Colombier ctlr->ndrive = nunit;
123757195852SDavid du Colombier ctlr->enabled = 0;
12384de34a7eSDavid du Colombier for(i = 0; i < ctlr->nchip; i++){
12394de34a7eSDavid du Colombier base = ctlr->mmio+0x20000+0x10000*i;
12404de34a7eSDavid du Colombier ctlr->chip[i].arb = (Arb*)base;
12414de34a7eSDavid du Colombier ctlr->chip[i].edma = (Edma*)(base + 0x2000);
12424de34a7eSDavid du Colombier }
124357195852SDavid du Colombier for (i = 0; i < nunit; i++) {
124457195852SDavid du Colombier d = &ctlr->drive[i];
124557195852SDavid du Colombier d->sectors = 0;
124657195852SDavid du Colombier d->ctlr = ctlr;
124757195852SDavid du Colombier d->driveno = ctlrno*NCtlrdrv + i;
124857195852SDavid du Colombier d->chipx = i%4;
124957195852SDavid du Colombier d->chip = &ctlr->chip[i/4];
125057195852SDavid du Colombier d->edma = &d->chip->edma[d->chipx];
125157195852SDavid du Colombier mvsatadrive[d->driveno] = d;
125257195852SDavid du Colombier }
125357195852SDavid du Colombier nmvsatadrive += nunit;
125457195852SDavid du Colombier ctlrno++;
12554de34a7eSDavid du Colombier if(head)
12564de34a7eSDavid du Colombier tail->next = sdev;
12574de34a7eSDavid du Colombier else
12584de34a7eSDavid du Colombier head = sdev;
12594de34a7eSDavid du Colombier tail = sdev;
12604de34a7eSDavid du Colombier }
12614de34a7eSDavid du Colombier return head;
12624de34a7eSDavid du Colombier }
12634de34a7eSDavid du Colombier
12644de34a7eSDavid du Colombier /*
12654de34a7eSDavid du Colombier * Enable the controller. Each disk has its own interrupt mask,
12664de34a7eSDavid du Colombier * and those get enabled as the disks are brought online.
12674de34a7eSDavid du Colombier */
12684de34a7eSDavid du Colombier static int
mv50enable(SDev * sdev)12694de34a7eSDavid du Colombier mv50enable(SDev *sdev)
12704de34a7eSDavid du Colombier {
12714de34a7eSDavid du Colombier char name[32];
12724de34a7eSDavid du Colombier Ctlr *ctlr;
12734de34a7eSDavid du Colombier
127457195852SDavid du Colombier dprint("sd%c: enable\n", sdev->idno);
12754de34a7eSDavid du Colombier
12764de34a7eSDavid du Colombier ctlr = sdev->ctlr;
127757195852SDavid du Colombier if (ctlr->enabled)
127857195852SDavid du Colombier return 1;
12794de34a7eSDavid du Colombier snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);
12804de34a7eSDavid du Colombier intrenable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);
128157195852SDavid du Colombier ctlr->enabled = 1;
12824de34a7eSDavid du Colombier return 1;
12834de34a7eSDavid du Colombier }
12844de34a7eSDavid du Colombier
12854de34a7eSDavid du Colombier /*
12864de34a7eSDavid du Colombier * Disable the controller.
12874de34a7eSDavid du Colombier */
12884de34a7eSDavid du Colombier static int
mv50disable(SDev * sdev)12894de34a7eSDavid du Colombier mv50disable(SDev *sdev)
12904de34a7eSDavid du Colombier {
12914de34a7eSDavid du Colombier char name[32];
12924de34a7eSDavid du Colombier int i;
12934de34a7eSDavid du Colombier Ctlr *ctlr;
12944de34a7eSDavid du Colombier Drive *drive;
12954de34a7eSDavid du Colombier
129657195852SDavid du Colombier dprint("sd%c: disable\n", sdev->idno);
12974de34a7eSDavid du Colombier
12984de34a7eSDavid du Colombier ctlr = sdev->ctlr;
12994de34a7eSDavid du Colombier ilock(ctlr);
13004de34a7eSDavid du Colombier for(i=0; i<ctlr->sdev->nunit; i++){
13014de34a7eSDavid du Colombier drive = &ctlr->drive[i];
13024de34a7eSDavid du Colombier ilock(drive);
13034de34a7eSDavid du Colombier disabledrive(drive);
13044de34a7eSDavid du Colombier iunlock(drive);
13054de34a7eSDavid du Colombier }
13064de34a7eSDavid du Colombier iunlock(ctlr);
13074de34a7eSDavid du Colombier snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);
13084de34a7eSDavid du Colombier intrdisable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);
13094de34a7eSDavid du Colombier return 0;
13104de34a7eSDavid du Colombier }
13114de34a7eSDavid du Colombier
13124de34a7eSDavid du Colombier /*
13134de34a7eSDavid du Colombier * Clean up all disk structures. Already disabled.
13144de34a7eSDavid du Colombier * Could keep count of number of allocated controllers
13154de34a7eSDavid du Colombier * and free the srblist when it drops to zero.
13164de34a7eSDavid du Colombier */
13174de34a7eSDavid du Colombier static void
mv50clear(SDev * sdev)13184de34a7eSDavid du Colombier mv50clear(SDev *sdev)
13194de34a7eSDavid du Colombier {
13204de34a7eSDavid du Colombier int i;
13214de34a7eSDavid du Colombier Ctlr *ctlr;
13224de34a7eSDavid du Colombier Drive *d;
13234de34a7eSDavid du Colombier
132457195852SDavid du Colombier dprint("sd%c: clear\n", sdev->idno);
13254de34a7eSDavid du Colombier
13264de34a7eSDavid du Colombier ctlr = sdev->ctlr;
13274de34a7eSDavid du Colombier for(i=0; i<ctlr->ndrive; i++){
13284de34a7eSDavid du Colombier d = &ctlr->drive[i];
13294de34a7eSDavid du Colombier free(d->tx);
13304de34a7eSDavid du Colombier free(d->rx);
13314de34a7eSDavid du Colombier free(d->prd);
13324de34a7eSDavid du Colombier }
13334de34a7eSDavid du Colombier free(ctlr);
13344de34a7eSDavid du Colombier }
13354de34a7eSDavid du Colombier
13364de34a7eSDavid du Colombier /*
13374de34a7eSDavid du Colombier * Check that there is a disk or at least a hot swap bay in the drive.
13384de34a7eSDavid du Colombier */
13394de34a7eSDavid du Colombier static int
mv50verify(SDunit * unit)13404de34a7eSDavid du Colombier mv50verify(SDunit *unit)
13414de34a7eSDavid du Colombier {
13424de34a7eSDavid du Colombier Ctlr *ctlr;
13434de34a7eSDavid du Colombier Drive *drive;
134457195852SDavid du Colombier int i;
13454de34a7eSDavid du Colombier
134657195852SDavid du Colombier dprint("%s: verify\n", unit->name);
13474de34a7eSDavid du Colombier ctlr = unit->dev->ctlr;
13484de34a7eSDavid du Colombier drive = &ctlr->drive[unit->subno];
13494de34a7eSDavid du Colombier ilock(ctlr);
13504de34a7eSDavid du Colombier ilock(drive);
135157195852SDavid du Colombier i = configdrive(ctlr, drive, unit);
13524de34a7eSDavid du Colombier iunlock(drive);
13534de34a7eSDavid du Colombier iunlock(ctlr);
135457195852SDavid du Colombier
13554de34a7eSDavid du Colombier /*
135657195852SDavid du Colombier * If ctlr->type == 1, then the drives spin up whenever
135757195852SDavid du Colombier * the controller feels like it; if ctlr->type != 1, then
135857195852SDavid du Colombier * they spin up as a result of configdrive.
135957195852SDavid du Colombier *
136057195852SDavid du Colombier * If there is a drive in the slot, give it 1.5s to spin up
136157195852SDavid du Colombier * before returning. There is a noticeable drag on the
136257195852SDavid du Colombier * power supply when spinning up fifteen drives
136357195852SDavid du Colombier * all at once (like in the Coraid enclosures).
13644de34a7eSDavid du Colombier */
136557195852SDavid du Colombier if(ctlr->type != 1 && i == 0){
136657195852SDavid du Colombier if(!waserror()){
136757195852SDavid du Colombier tsleep(&up->sleep, return0, 0, 1500);
136857195852SDavid du Colombier poperror();
136957195852SDavid du Colombier }
137057195852SDavid du Colombier }
13714de34a7eSDavid du Colombier return 1;
13724de34a7eSDavid du Colombier }
13734de34a7eSDavid du Colombier
13744de34a7eSDavid du Colombier /*
13754de34a7eSDavid du Colombier * Check whether the disk is online.
13764de34a7eSDavid du Colombier */
13774de34a7eSDavid du Colombier static int
mv50online(SDunit * unit)13784de34a7eSDavid du Colombier mv50online(SDunit *unit)
13794de34a7eSDavid du Colombier {
13804de34a7eSDavid du Colombier Ctlr *ctlr;
138157195852SDavid du Colombier Drive *d;
138257195852SDavid du Colombier int r, s0;
138357195852SDavid du Colombier static int once;
138457195852SDavid du Colombier
138557195852SDavid du Colombier if(once++ == 0)
138657195852SDavid du Colombier kproc("mvsata", satakproc, 0);
13874de34a7eSDavid du Colombier
13884de34a7eSDavid du Colombier ctlr = unit->dev->ctlr;
138957195852SDavid du Colombier d = &ctlr->drive[unit->subno];
139057195852SDavid du Colombier r = 0;
139157195852SDavid du Colombier ilock(d);
139257195852SDavid du Colombier s0 = d->state;
139357195852SDavid du Colombier USED(s0);
139457195852SDavid du Colombier if(d->state == Dnew)
139557195852SDavid du Colombier identifydrive(d);
139657195852SDavid du Colombier if(d->mediachange){
139757195852SDavid du Colombier idprint("%s: online: %s -> %s\n", unit->name, diskstates[s0], diskstates[d->state]);
139857195852SDavid du Colombier r = 2;
139957195852SDavid du Colombier unit->sectors = d->sectors;
14004de34a7eSDavid du Colombier unit->secsize = 512;
140157195852SDavid du Colombier d->mediachange = 0;
140257195852SDavid du Colombier } else if(d->state == Dready)
140357195852SDavid du Colombier r = 1;
140457195852SDavid du Colombier iunlock(d);
140557195852SDavid du Colombier return r;
14064de34a7eSDavid du Colombier }
14074de34a7eSDavid du Colombier
14084de34a7eSDavid du Colombier /*
14094de34a7eSDavid du Colombier * Register dumps
14104de34a7eSDavid du Colombier */
14114de34a7eSDavid du Colombier typedef struct Regs Regs;
14124de34a7eSDavid du Colombier struct Regs
14134de34a7eSDavid du Colombier {
14144de34a7eSDavid du Colombier ulong offset;
14154de34a7eSDavid du Colombier char *name;
14164de34a7eSDavid du Colombier };
14174de34a7eSDavid du Colombier
14184de34a7eSDavid du Colombier static Regs regsctlr[] =
14194de34a7eSDavid du Colombier {
14204de34a7eSDavid du Colombier 0x0C28, "pci serr# mask",
14214de34a7eSDavid du Colombier 0x1D40, "pci err addr low",
14224de34a7eSDavid du Colombier 0x1D44, "pci err addr hi",
14234de34a7eSDavid du Colombier 0x1D48, "pci err attr",
14244de34a7eSDavid du Colombier 0x1D50, "pci err cmd",
14254de34a7eSDavid du Colombier 0x1D58, "pci intr cause",
14264de34a7eSDavid du Colombier 0x1D5C, "pci mask cause",
14274de34a7eSDavid du Colombier 0x1D60, "device micr",
14284de34a7eSDavid du Colombier 0x1D64, "device mimr",
14294de34a7eSDavid du Colombier };
14304de34a7eSDavid du Colombier
14314de34a7eSDavid du Colombier static Regs regsarb[] =
14324de34a7eSDavid du Colombier {
14334de34a7eSDavid du Colombier 0x0004, "arb rqop",
14344de34a7eSDavid du Colombier 0x0008, "arb rqip",
14354de34a7eSDavid du Colombier 0x000C, "arb ict",
14364de34a7eSDavid du Colombier 0x0010, "arb itt",
14374de34a7eSDavid du Colombier 0x0014, "arb ic",
14384de34a7eSDavid du Colombier 0x0018, "arb btc",
14394de34a7eSDavid du Colombier 0x001C, "arb bts",
14404de34a7eSDavid du Colombier 0x0020, "arb bpc",
14414de34a7eSDavid du Colombier };
14424de34a7eSDavid du Colombier
14434de34a7eSDavid du Colombier static Regs regsbridge[] =
14444de34a7eSDavid du Colombier {
14454de34a7eSDavid du Colombier 0x0000, "bridge status",
14464de34a7eSDavid du Colombier 0x0004, "bridge serror",
14474de34a7eSDavid du Colombier 0x0008, "bridge sctrl",
14484de34a7eSDavid du Colombier 0x000C, "bridge phyctrl",
14494de34a7eSDavid du Colombier 0x003C, "bridge ctrl",
14504de34a7eSDavid du Colombier 0x0074, "bridge phymode",
14514de34a7eSDavid du Colombier };
14524de34a7eSDavid du Colombier
14534de34a7eSDavid du Colombier static Regs regsedma[] =
14544de34a7eSDavid du Colombier {
14554de34a7eSDavid du Colombier 0x0000, "edma config",
14564de34a7eSDavid du Colombier 0x0004, "edma timer",
14574de34a7eSDavid du Colombier 0x0008, "edma iec",
14584de34a7eSDavid du Colombier 0x000C, "edma iem",
14594de34a7eSDavid du Colombier 0x0010, "edma txbasehi",
14604de34a7eSDavid du Colombier 0x0014, "edma txi",
14614de34a7eSDavid du Colombier 0x0018, "edma txo",
14624de34a7eSDavid du Colombier 0x001C, "edma rxbasehi",
14634de34a7eSDavid du Colombier 0x0020, "edma rxi",
14644de34a7eSDavid du Colombier 0x0024, "edma rxo",
14654de34a7eSDavid du Colombier 0x0028, "edma c",
14664de34a7eSDavid du Colombier 0x002C, "edma tc",
14674de34a7eSDavid du Colombier 0x0030, "edma status",
14684de34a7eSDavid du Colombier 0x0034, "edma iordyto",
14694de34a7eSDavid du Colombier /* 0x0100, "edma pio",
14704de34a7eSDavid du Colombier 0x0104, "edma err",
14714de34a7eSDavid du Colombier 0x0108, "edma sectors",
14724de34a7eSDavid du Colombier 0x010C, "edma lba0",
14734de34a7eSDavid du Colombier 0x0110, "edma lba1",
14744de34a7eSDavid du Colombier 0x0114, "edma lba2",
14754de34a7eSDavid du Colombier 0x0118, "edma lba3",
14764de34a7eSDavid du Colombier 0x011C, "edma cmdstat",
14774de34a7eSDavid du Colombier 0x0120, "edma altstat",
14784de34a7eSDavid du Colombier */
14794de34a7eSDavid du Colombier };
14804de34a7eSDavid du Colombier
14814de34a7eSDavid du Colombier static char*
rdregs(char * p,char * e,void * base,Regs * r,int n,char * prefix)14824de34a7eSDavid du Colombier rdregs(char *p, char *e, void *base, Regs *r, int n, char *prefix)
14834de34a7eSDavid du Colombier {
14844de34a7eSDavid du Colombier int i;
14854de34a7eSDavid du Colombier
14864de34a7eSDavid du Colombier for(i = 0; i < n; i++)
1487*ea58ad6fSDavid du Colombier p = seprint(p, e, "%s%s%-19s %.8lux\n",
14884de34a7eSDavid du Colombier prefix? prefix: "", prefix? ": ": "",
148991b330d9SDavid du Colombier r[i].name, *(ulong *)((uchar*)base + r[i].offset));
14904de34a7eSDavid du Colombier return p;
14914de34a7eSDavid du Colombier }
14924de34a7eSDavid du Colombier
14934de34a7eSDavid du Colombier static char*
rdinfo(char * p,char * e,ushort * info)14944de34a7eSDavid du Colombier rdinfo(char *p, char *e, ushort *info)
14954de34a7eSDavid du Colombier {
14964de34a7eSDavid du Colombier int i;
14974de34a7eSDavid du Colombier
14984de34a7eSDavid du Colombier p = seprint(p, e, "info");
1499*ea58ad6fSDavid du Colombier for(i = 0; i < 256; i++)
1500*ea58ad6fSDavid du Colombier p = seprint(p, e, "%s%.4ux%s", i%8 == 0? "\t": "", info[i],
15014de34a7eSDavid du Colombier i%8 == 7? "\n": "");
15024de34a7eSDavid du Colombier return p;
15034de34a7eSDavid du Colombier }
15044de34a7eSDavid du Colombier
15054de34a7eSDavid du Colombier static int
mv50rctl(SDunit * unit,char * p,int l)15064de34a7eSDavid du Colombier mv50rctl(SDunit *unit, char *p, int l)
15074de34a7eSDavid du Colombier {
15084de34a7eSDavid du Colombier char *e, *op;
15094de34a7eSDavid du Colombier Ctlr *ctlr;
15104de34a7eSDavid du Colombier Drive *drive;
15114de34a7eSDavid du Colombier
15124de34a7eSDavid du Colombier if((ctlr = unit->dev->ctlr) == nil)
15134de34a7eSDavid du Colombier return 0;
15144de34a7eSDavid du Colombier drive = &ctlr->drive[unit->subno];
15154de34a7eSDavid du Colombier
15164de34a7eSDavid du Colombier e = p+l;
15174de34a7eSDavid du Colombier op = p;
15184de34a7eSDavid du Colombier if(drive->state == Dready){
15194de34a7eSDavid du Colombier p = seprint(p, e, "model %s\n", drive->model);
15204de34a7eSDavid du Colombier p = seprint(p, e, "serial %s\n", drive->serial);
15214de34a7eSDavid du Colombier p = seprint(p, e, "firmware %s\n", drive->firmware);
15224de34a7eSDavid du Colombier }else
15234de34a7eSDavid du Colombier p = seprint(p, e, "no disk present\n");
15244de34a7eSDavid du Colombier p = seprint(p, e, "geometry %llud 512\n", drive->sectors);
15254de34a7eSDavid du Colombier p = rdinfo(p, e, drive->info);
15264de34a7eSDavid du Colombier
15274de34a7eSDavid du Colombier p = rdregs(p, e, drive->chip->arb, regsarb, nelem(regsarb), nil);
15284de34a7eSDavid du Colombier p = rdregs(p, e, drive->bridge, regsbridge, nelem(regsbridge), nil);
15294de34a7eSDavid du Colombier p = rdregs(p, e, drive->edma, regsedma, nelem(regsedma), nil);
15304de34a7eSDavid du Colombier
15314de34a7eSDavid du Colombier return p-op;
15324de34a7eSDavid du Colombier }
15334de34a7eSDavid du Colombier
15344de34a7eSDavid du Colombier static int
mv50wctl(SDunit * unit,Cmdbuf * cb)15354de34a7eSDavid du Colombier mv50wctl(SDunit *unit, Cmdbuf *cb)
15364de34a7eSDavid du Colombier {
15374de34a7eSDavid du Colombier Ctlr *ctlr;
15384de34a7eSDavid du Colombier Drive *drive;
15394de34a7eSDavid du Colombier
15404de34a7eSDavid du Colombier USED(unit);
15414de34a7eSDavid du Colombier if(strcmp(cb->f[0], "reset") == 0){
15424de34a7eSDavid du Colombier ctlr = unit->dev->ctlr;
15434de34a7eSDavid du Colombier drive = &ctlr->drive[unit->subno];
15444de34a7eSDavid du Colombier ilock(drive);
154557195852SDavid du Colombier drive->state = Dreset;
15464de34a7eSDavid du Colombier iunlock(drive);
15474de34a7eSDavid du Colombier return 0;
15484de34a7eSDavid du Colombier }
15494de34a7eSDavid du Colombier cmderror(cb, Ebadctl);
15504de34a7eSDavid du Colombier return -1;
15514de34a7eSDavid du Colombier }
15524de34a7eSDavid du Colombier
1553*ea58ad6fSDavid du Colombier /*
1554*ea58ad6fSDavid du Colombier * sd(3): ``Reading /dev/sdctl yields information about each controller,
1555*ea58ad6fSDavid du Colombier * one line per controller.''
1556*ea58ad6fSDavid du Colombier */
15574de34a7eSDavid du Colombier static char*
mv50rtopctl(SDev * sdev,char * p,char * e)15584de34a7eSDavid du Colombier mv50rtopctl(SDev *sdev, char *p, char *e)
15594de34a7eSDavid du Colombier {
15604de34a7eSDavid du Colombier char name[10];
15614de34a7eSDavid du Colombier Ctlr *ctlr;
15624de34a7eSDavid du Colombier
15634de34a7eSDavid du Colombier ctlr = sdev->ctlr;
15644de34a7eSDavid du Colombier if(ctlr == nil)
15654de34a7eSDavid du Colombier return p;
15664de34a7eSDavid du Colombier
15674de34a7eSDavid du Colombier snprint(name, sizeof name, "sd%c", sdev->idno);
15684de34a7eSDavid du Colombier p = rdregs(p, e, ctlr->mmio, regsctlr, nelem(regsctlr), name);
1569*ea58ad6fSDavid du Colombier if (Coraiddebug) {
1570*ea58ad6fSDavid du Colombier /* info for first disk. BUG: this shouldn't be here. */
1571*ea58ad6fSDavid du Colombier p = rdregs(p, e, ctlr->chip[0].arb,
1572*ea58ad6fSDavid du Colombier regsarb, nelem(regsarb), name);
1573*ea58ad6fSDavid du Colombier p = rdregs(p, e, &ctlr->chip[0].arb->bridge[0],
1574*ea58ad6fSDavid du Colombier regsbridge, nelem(regsbridge), name);
1575*ea58ad6fSDavid du Colombier p = rdregs(p, e, &ctlr->chip[0].edma[0],
1576*ea58ad6fSDavid du Colombier regsedma, nelem(regsedma), name);
1577*ea58ad6fSDavid du Colombier }
15784de34a7eSDavid du Colombier return p;
15794de34a7eSDavid du Colombier }
15804de34a7eSDavid du Colombier
15814de34a7eSDavid du Colombier static int
waitready(Drive * d)158257195852SDavid du Colombier waitready(Drive *d)
158357195852SDavid du Colombier {
158457195852SDavid du Colombier ulong s, i;
158557195852SDavid du Colombier
158657195852SDavid du Colombier for(i = 0; i < 120; i++){
158757195852SDavid du Colombier ilock(d);
158857195852SDavid du Colombier s = d->bridge->status;
158957195852SDavid du Colombier iunlock(d);
159057195852SDavid du Colombier if(s == 0)
159157195852SDavid du Colombier return SDeio;
159257195852SDavid du Colombier if (d->state == Dready)
159357195852SDavid du Colombier return SDok;
159457195852SDavid du Colombier if ((i+1)%60 == 0){
159557195852SDavid du Colombier ilock(d);
159657195852SDavid du Colombier resetdisk(d);
159757195852SDavid du Colombier iunlock(d);
159857195852SDavid du Colombier }
159957195852SDavid du Colombier if(!waserror()){
160057195852SDavid du Colombier tsleep(&up->sleep, return0, 0, 1000);
160157195852SDavid du Colombier poperror();
160257195852SDavid du Colombier }
160357195852SDavid du Colombier }
160457195852SDavid du Colombier print("%s: not responding after 2 minutes\n", d->unit->name);
160557195852SDavid du Colombier return SDeio;
160657195852SDavid du Colombier }
160757195852SDavid du Colombier
160857195852SDavid du Colombier static int
mv50rio(SDreq * r)16094de34a7eSDavid du Colombier mv50rio(SDreq *r)
16104de34a7eSDavid du Colombier {
161157195852SDavid du Colombier int count, max, n, status, try, flag;
16124de34a7eSDavid du Colombier uchar *cmd, *data;
16134de34a7eSDavid du Colombier uvlong lba;
16144de34a7eSDavid du Colombier Ctlr *ctlr;
16154de34a7eSDavid du Colombier Drive *drive;
16164de34a7eSDavid du Colombier SDunit *unit;
16174de34a7eSDavid du Colombier Srb *srb;
16184de34a7eSDavid du Colombier
16194de34a7eSDavid du Colombier unit = r->unit;
16204de34a7eSDavid du Colombier ctlr = unit->dev->ctlr;
16214de34a7eSDavid du Colombier drive = &ctlr->drive[unit->subno];
16224de34a7eSDavid du Colombier cmd = r->cmd;
16234de34a7eSDavid du Colombier
16244de34a7eSDavid du Colombier if((status = sdfakescsi(r, drive->info, sizeof drive->info)) != SDnostatus){
16254de34a7eSDavid du Colombier /* XXX check for SDcheck here */
16264de34a7eSDavid du Colombier r->status = status;
16274de34a7eSDavid du Colombier return status;
16284de34a7eSDavid du Colombier }
16294de34a7eSDavid du Colombier
16304de34a7eSDavid du Colombier switch(cmd[0]){
16314de34a7eSDavid du Colombier case 0x28: /* read */
16324de34a7eSDavid du Colombier case 0x2A: /* write */
16334de34a7eSDavid du Colombier break;
16344de34a7eSDavid du Colombier default:
163557195852SDavid du Colombier iprint("%s: bad cmd 0x%.2ux\n", drive->unit->name, cmd[0]);
16364de34a7eSDavid du Colombier r->status = SDcheck;
16374de34a7eSDavid du Colombier return SDcheck;
16384de34a7eSDavid du Colombier }
16394de34a7eSDavid du Colombier
16404de34a7eSDavid du Colombier lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5];
16414de34a7eSDavid du Colombier count = (cmd[7]<<8)|cmd[8];
16424de34a7eSDavid du Colombier if(r->data == nil)
16434de34a7eSDavid du Colombier return SDok;
16444de34a7eSDavid du Colombier if(r->dlen < count*unit->secsize)
16454de34a7eSDavid du Colombier count = r->dlen/unit->secsize;
16464de34a7eSDavid du Colombier
164757195852SDavid du Colombier try = 0;
164857195852SDavid du Colombier retry:
164957195852SDavid du Colombier if(waitready(drive) != SDok)
165057195852SDavid du Colombier return SDeio;
16514de34a7eSDavid du Colombier /*
16524de34a7eSDavid du Colombier * Could arrange here to have an Srb always outstanding:
16534de34a7eSDavid du Colombier *
16544de34a7eSDavid du Colombier * lsrb = nil;
16554de34a7eSDavid du Colombier * while(count > 0 || lsrb != nil){
16564de34a7eSDavid du Colombier * srb = nil;
16574de34a7eSDavid du Colombier * if(count > 0){
16584de34a7eSDavid du Colombier * srb = issue next srb;
16594de34a7eSDavid du Colombier * }
16604de34a7eSDavid du Colombier * if(lsrb){
16614de34a7eSDavid du Colombier * sleep on lsrb and handle it
16624de34a7eSDavid du Colombier * }
16634de34a7eSDavid du Colombier * }
16644de34a7eSDavid du Colombier *
16654de34a7eSDavid du Colombier * On the disks I tried, this didn't help. If anything,
16664de34a7eSDavid du Colombier * it's a little slower. -rsc
16674de34a7eSDavid du Colombier */
16684de34a7eSDavid du Colombier data = r->data;
16694de34a7eSDavid du Colombier while(count > 0){
16704de34a7eSDavid du Colombier /*
16714de34a7eSDavid du Colombier * Max is 128 sectors (64kB) because prd->count is 16 bits.
16724de34a7eSDavid du Colombier */
16734de34a7eSDavid du Colombier max = 128;
16744de34a7eSDavid du Colombier n = count;
16754de34a7eSDavid du Colombier if(n > max)
16764de34a7eSDavid du Colombier n = max;
167757195852SDavid du Colombier if((drive->edma->ctl&eEnEDMA) == 0)
167857195852SDavid du Colombier goto tryagain;
16794de34a7eSDavid du Colombier srb = srbrw(cmd[0]==0x28 ? SRBread : SRBwrite, drive, data, n, lba);
16804de34a7eSDavid du Colombier ilock(drive);
16814de34a7eSDavid du Colombier startsrb(drive, srb);
16824de34a7eSDavid du Colombier iunlock(drive);
16834de34a7eSDavid du Colombier
168457195852SDavid du Colombier /* Don't let user interrupt DMA. */
16854de34a7eSDavid du Colombier while(waserror())
16864de34a7eSDavid du Colombier ;
168757195852SDavid du Colombier sleep(srb, srbdone, srb);
16884de34a7eSDavid du Colombier poperror();
16894de34a7eSDavid du Colombier
169057195852SDavid du Colombier flag = srb->flag;
16914de34a7eSDavid du Colombier freesrb(srb);
169257195852SDavid du Colombier if(flag == 0){
169391b330d9SDavid du Colombier tryagain:
169491b330d9SDavid du Colombier if(++try == 10){
169557195852SDavid du Colombier print("%s: bad disk\n", drive->unit->name);
169657195852SDavid du Colombier return SDeio;
16974de34a7eSDavid du Colombier }
169857195852SDavid du Colombier dprint("%s: retry\n", drive->unit->name);
169957195852SDavid du Colombier if(!waserror()){
170057195852SDavid du Colombier tsleep(&up->sleep, return0, 0, 1000);
170157195852SDavid du Colombier poperror();
17024de34a7eSDavid du Colombier }
170357195852SDavid du Colombier goto retry;
17044de34a7eSDavid du Colombier }
170557195852SDavid du Colombier if(flag & SFerror){
170657195852SDavid du Colombier print("%s: i/o error\n", drive->unit->name);
170757195852SDavid du Colombier return SDeio;
170857195852SDavid du Colombier }
17094de34a7eSDavid du Colombier count -= n;
17104de34a7eSDavid du Colombier lba += n;
17114de34a7eSDavid du Colombier data += n*unit->secsize;
17124de34a7eSDavid du Colombier }
17134de34a7eSDavid du Colombier r->rlen = data - (uchar*)r->data;
17144de34a7eSDavid du Colombier return SDok;
17154de34a7eSDavid du Colombier }
17164de34a7eSDavid du Colombier
17174de34a7eSDavid du Colombier SDifc sdmv50xxifc = {
17184de34a7eSDavid du Colombier "mv50xx", /* name */
17194de34a7eSDavid du Colombier
17204de34a7eSDavid du Colombier mv50pnp, /* pnp */
17214de34a7eSDavid du Colombier nil, /* legacy */
17224de34a7eSDavid du Colombier mv50enable, /* enable */
17234de34a7eSDavid du Colombier mv50disable, /* disable */
17244de34a7eSDavid du Colombier
17254de34a7eSDavid du Colombier mv50verify, /* verify */
17264de34a7eSDavid du Colombier mv50online, /* online */
17274de34a7eSDavid du Colombier mv50rio, /* rio */
17284de34a7eSDavid du Colombier mv50rctl, /* rctl */
17294de34a7eSDavid du Colombier mv50wctl, /* wctl */
17304de34a7eSDavid du Colombier
17314de34a7eSDavid du Colombier scsibio, /* bio */
17324de34a7eSDavid du Colombier nil, /* probe */
17334de34a7eSDavid du Colombier mv50clear, /* clear */
17344de34a7eSDavid du Colombier mv50rtopctl, /* rtopctl */
17354de34a7eSDavid du Colombier };
17364de34a7eSDavid du Colombier
17374de34a7eSDavid du Colombier /*
17384de34a7eSDavid du Colombier * The original driver on which this one is based came with the
17394de34a7eSDavid du Colombier * following notice:
17404de34a7eSDavid du Colombier *
17414de34a7eSDavid du Colombier * Copyright 2005
17424de34a7eSDavid du Colombier * Coraid, Inc.
17434de34a7eSDavid du Colombier *
17444de34a7eSDavid du Colombier * This software is provided `as-is,' without any express or implied
17454de34a7eSDavid du Colombier * warranty. In no event will the author be held liable for any damages
17464de34a7eSDavid du Colombier * arising from the use of this software.
17474de34a7eSDavid du Colombier *
17484de34a7eSDavid du Colombier * Permission is granted to anyone to use this software for any purpose,
17494de34a7eSDavid du Colombier * including commercial applications, and to alter it and redistribute it
17504de34a7eSDavid du Colombier * freely, subject to the following restrictions:
17514de34a7eSDavid du Colombier *
17524de34a7eSDavid du Colombier * 1. The origin of this software must not be misrepresented; you must
17534de34a7eSDavid du Colombier * not claim that you wrote the original software. If you use this
17544de34a7eSDavid du Colombier * software in a product, an acknowledgment in the product documentation
17554de34a7eSDavid du Colombier * would be appreciated but is not required.
17564de34a7eSDavid du Colombier *
17574de34a7eSDavid du Colombier * 2. Altered source versions must be plainly marked as such, and must
17584de34a7eSDavid du Colombier * not be misrepresented as being the original software.
17594de34a7eSDavid du Colombier *
17604de34a7eSDavid du Colombier * 3. This notice may not be removed or altered from any source
17614de34a7eSDavid du Colombier * distribution.
17624de34a7eSDavid du Colombier */
1763