1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "io.h"
7*74a4d8c2SCharles.Forsyth #include "../port/error.h"
8*74a4d8c2SCharles.Forsyth
9*74a4d8c2SCharles.Forsyth #include "pcmcia.h"
10*74a4d8c2SCharles.Forsyth
11*74a4d8c2SCharles.Forsyth #define DPRINT if(0)print
12*74a4d8c2SCharles.Forsyth
13*74a4d8c2SCharles.Forsyth typedef struct Drive Drive;
14*74a4d8c2SCharles.Forsyth typedef struct Ident Ident;
15*74a4d8c2SCharles.Forsyth typedef struct Controller Controller;
16*74a4d8c2SCharles.Forsyth typedef struct Partition Partition;
17*74a4d8c2SCharles.Forsyth typedef struct Repl Repl;
18*74a4d8c2SCharles.Forsyth
19*74a4d8c2SCharles.Forsyth enum
20*74a4d8c2SCharles.Forsyth {
21*74a4d8c2SCharles.Forsyth /* ports */
22*74a4d8c2SCharles.Forsyth Pbase= 0x1F0,
23*74a4d8c2SCharles.Forsyth Pdata= 0, /* data port (16 bits) */
24*74a4d8c2SCharles.Forsyth Perror= 1, /* error port (read) */
25*74a4d8c2SCharles.Forsyth Pprecomp= 1, /* buffer mode port (write) */
26*74a4d8c2SCharles.Forsyth Pcount= 2, /* sector count port */
27*74a4d8c2SCharles.Forsyth Psector= 3, /* sector number port */
28*74a4d8c2SCharles.Forsyth Pcyllsb= 4, /* least significant byte cylinder # */
29*74a4d8c2SCharles.Forsyth Pcylmsb= 5, /* most significant byte cylinder # */
30*74a4d8c2SCharles.Forsyth Pdh= 6, /* drive/head port */
31*74a4d8c2SCharles.Forsyth Pstatus= 7, /* status port (read) */
32*74a4d8c2SCharles.Forsyth Sbusy= (1<<7),
33*74a4d8c2SCharles.Forsyth Sready= (1<<6),
34*74a4d8c2SCharles.Forsyth Sdrq= (1<<3),
35*74a4d8c2SCharles.Forsyth Serr= (1<<0),
36*74a4d8c2SCharles.Forsyth Pcmd= 7, /* cmd port (write) */
37*74a4d8c2SCharles.Forsyth
38*74a4d8c2SCharles.Forsyth /* commands */
39*74a4d8c2SCharles.Forsyth Crecal= 0x10,
40*74a4d8c2SCharles.Forsyth Cread= 0x20,
41*74a4d8c2SCharles.Forsyth Cwrite= 0x30,
42*74a4d8c2SCharles.Forsyth Cident= 0xEC,
43*74a4d8c2SCharles.Forsyth Cident2= 0xFF, /* pseudo command for post Cident interrupt */
44*74a4d8c2SCharles.Forsyth Csetbuf= 0xEF,
45*74a4d8c2SCharles.Forsyth Cinitparam= 0x91,
46*74a4d8c2SCharles.Forsyth
47*74a4d8c2SCharles.Forsyth /* conner specific commands */
48*74a4d8c2SCharles.Forsyth Cstandby= 0xE2,
49*74a4d8c2SCharles.Forsyth Cidle= 0xE1,
50*74a4d8c2SCharles.Forsyth Cpowerdown= 0xE3,
51*74a4d8c2SCharles.Forsyth
52*74a4d8c2SCharles.Forsyth /* disk states */
53*74a4d8c2SCharles.Forsyth Sspinning,
54*74a4d8c2SCharles.Forsyth Sstandby,
55*74a4d8c2SCharles.Forsyth Sidle,
56*74a4d8c2SCharles.Forsyth Spowerdown,
57*74a4d8c2SCharles.Forsyth
58*74a4d8c2SCharles.Forsyth /* something we have to or into the drive/head reg */
59*74a4d8c2SCharles.Forsyth DHmagic= 0xA0,
60*74a4d8c2SCharles.Forsyth
61*74a4d8c2SCharles.Forsyth /* file types */
62*74a4d8c2SCharles.Forsyth Qdir= 0,
63*74a4d8c2SCharles.Forsyth
64*74a4d8c2SCharles.Forsyth Maxxfer= BY2PG, /* maximum transfer size/cmd */
65*74a4d8c2SCharles.Forsyth Npart= 8+2, /* 8 sub partitions, disk, and partition */
66*74a4d8c2SCharles.Forsyth Nrepl= 64, /* maximum replacement blocks */
67*74a4d8c2SCharles.Forsyth };
68*74a4d8c2SCharles.Forsyth #define PART(x) ((x)&0xF)
69*74a4d8c2SCharles.Forsyth #define DRIVE(x) (((x)>>4)&0x7)
70*74a4d8c2SCharles.Forsyth #define MKQID(d,p) (((d)<<4) | (p))
71*74a4d8c2SCharles.Forsyth
72*74a4d8c2SCharles.Forsyth struct Partition
73*74a4d8c2SCharles.Forsyth {
74*74a4d8c2SCharles.Forsyth ulong start;
75*74a4d8c2SCharles.Forsyth ulong end;
76*74a4d8c2SCharles.Forsyth char name[NAMELEN+1];
77*74a4d8c2SCharles.Forsyth };
78*74a4d8c2SCharles.Forsyth
79*74a4d8c2SCharles.Forsyth struct Repl
80*74a4d8c2SCharles.Forsyth {
81*74a4d8c2SCharles.Forsyth Partition *p;
82*74a4d8c2SCharles.Forsyth int nrepl;
83*74a4d8c2SCharles.Forsyth ulong blk[Nrepl];
84*74a4d8c2SCharles.Forsyth };
85*74a4d8c2SCharles.Forsyth
86*74a4d8c2SCharles.Forsyth #define PARTMAGIC "plan9 partitions"
87*74a4d8c2SCharles.Forsyth #define REPLMAGIC "block replacements"
88*74a4d8c2SCharles.Forsyth
89*74a4d8c2SCharles.Forsyth /*
90*74a4d8c2SCharles.Forsyth * an ata drive
91*74a4d8c2SCharles.Forsyth */
92*74a4d8c2SCharles.Forsyth struct Drive
93*74a4d8c2SCharles.Forsyth {
94*74a4d8c2SCharles.Forsyth QLock;
95*74a4d8c2SCharles.Forsyth
96*74a4d8c2SCharles.Forsyth Controller *cp;
97*74a4d8c2SCharles.Forsyth int drive;
98*74a4d8c2SCharles.Forsyth int confused; /* needs to be recalibrated (or worse) */
99*74a4d8c2SCharles.Forsyth int online;
100*74a4d8c2SCharles.Forsyth int npart; /* number of real partitions */
101*74a4d8c2SCharles.Forsyth Partition p[Npart];
102*74a4d8c2SCharles.Forsyth Repl repl;
103*74a4d8c2SCharles.Forsyth ulong usetime;
104*74a4d8c2SCharles.Forsyth int state;
105*74a4d8c2SCharles.Forsyth char vol[NAMELEN];
106*74a4d8c2SCharles.Forsyth
107*74a4d8c2SCharles.Forsyth ulong cap; /* total bytes */
108*74a4d8c2SCharles.Forsyth int bytes; /* bytes/sector */
109*74a4d8c2SCharles.Forsyth int sectors; /* sectors/track */
110*74a4d8c2SCharles.Forsyth int heads; /* heads/cyl */
111*74a4d8c2SCharles.Forsyth long cyl; /* cylinders/drive */
112*74a4d8c2SCharles.Forsyth
113*74a4d8c2SCharles.Forsyth char lba; /* true if drive has logical block addressing */
114*74a4d8c2SCharles.Forsyth char multi; /* non-zero if drive does multiple block xfers */
115*74a4d8c2SCharles.Forsyth };
116*74a4d8c2SCharles.Forsyth
117*74a4d8c2SCharles.Forsyth /*
118*74a4d8c2SCharles.Forsyth * a controller for 2 drives
119*74a4d8c2SCharles.Forsyth */
120*74a4d8c2SCharles.Forsyth struct Controller
121*74a4d8c2SCharles.Forsyth {
122*74a4d8c2SCharles.Forsyth QLock; /* exclusive access to the controller */
123*74a4d8c2SCharles.Forsyth ISAConf; /* interface to pcmspecial */
124*74a4d8c2SCharles.Forsyth
125*74a4d8c2SCharles.Forsyth Lock reglock; /* exclusive access to the registers */
126*74a4d8c2SCharles.Forsyth
127*74a4d8c2SCharles.Forsyth int confused; /* needs to be recalibrated (or worse) */
128*74a4d8c2SCharles.Forsyth ulong pbase; /* base port (copied from ISAConf) */
129*74a4d8c2SCharles.Forsyth
130*74a4d8c2SCharles.Forsyth /*
131*74a4d8c2SCharles.Forsyth * current operation
132*74a4d8c2SCharles.Forsyth */
133*74a4d8c2SCharles.Forsyth int cmd; /* current command */
134*74a4d8c2SCharles.Forsyth int lastcmd; /* debugging info */
135*74a4d8c2SCharles.Forsyth Rendez r; /* wait here for command termination */
136*74a4d8c2SCharles.Forsyth char *buf; /* xfer buffer */
137*74a4d8c2SCharles.Forsyth int nsecs; /* length of transfer (sectors) */
138*74a4d8c2SCharles.Forsyth int sofar; /* sectors transferred so far */
139*74a4d8c2SCharles.Forsyth int status;
140*74a4d8c2SCharles.Forsyth int error;
141*74a4d8c2SCharles.Forsyth Drive *dp; /* drive being accessed */
142*74a4d8c2SCharles.Forsyth };
143*74a4d8c2SCharles.Forsyth
144*74a4d8c2SCharles.Forsyth Controller *atac;
145*74a4d8c2SCharles.Forsyth Drive *ata;
146*74a4d8c2SCharles.Forsyth static char* ataerr;
147*74a4d8c2SCharles.Forsyth static int nhard;
148*74a4d8c2SCharles.Forsyth static int spindowntime;
149*74a4d8c2SCharles.Forsyth
150*74a4d8c2SCharles.Forsyth static void ataintr(Ureg*, void*);
151*74a4d8c2SCharles.Forsyth static long ataxfer(Drive*, Partition*, int, long, long, char*);
152*74a4d8c2SCharles.Forsyth static void ataident(Drive*);
153*74a4d8c2SCharles.Forsyth static void atasetbuf(Drive*, int);
154*74a4d8c2SCharles.Forsyth static void ataparams(Drive*);
155*74a4d8c2SCharles.Forsyth static void atapart(Drive*);
156*74a4d8c2SCharles.Forsyth static int ataprobe(Drive*, int, int, int);
157*74a4d8c2SCharles.Forsyth
158*74a4d8c2SCharles.Forsyth static int
atagen(Chan * c,Dirtab *,int,int s,Dir * dirp)159*74a4d8c2SCharles.Forsyth atagen(Chan *c, Dirtab*, int, int s, Dir *dirp)
160*74a4d8c2SCharles.Forsyth {
161*74a4d8c2SCharles.Forsyth Qid qid;
162*74a4d8c2SCharles.Forsyth int drive;
163*74a4d8c2SCharles.Forsyth Drive *dp;
164*74a4d8c2SCharles.Forsyth Partition *pp;
165*74a4d8c2SCharles.Forsyth ulong l;
166*74a4d8c2SCharles.Forsyth
167*74a4d8c2SCharles.Forsyth qid.vers = 0;
168*74a4d8c2SCharles.Forsyth drive = s/Npart;
169*74a4d8c2SCharles.Forsyth s = s % Npart;
170*74a4d8c2SCharles.Forsyth if(drive >= nhard)
171*74a4d8c2SCharles.Forsyth return -1;
172*74a4d8c2SCharles.Forsyth dp = &ata[drive];
173*74a4d8c2SCharles.Forsyth
174*74a4d8c2SCharles.Forsyth if(dp->online == 0 || s >= dp->npart)
175*74a4d8c2SCharles.Forsyth return 0;
176*74a4d8c2SCharles.Forsyth
177*74a4d8c2SCharles.Forsyth pp = &dp->p[s];
178*74a4d8c2SCharles.Forsyth sprint(up->genbuf, "%s%s", dp->vol, pp->name);
179*74a4d8c2SCharles.Forsyth qid.path = MKQID(drive, s);
180*74a4d8c2SCharles.Forsyth l = (pp->end - pp->start) * dp->bytes;
181*74a4d8c2SCharles.Forsyth devdir(c, qid, up->genbuf, l, eve, 0660, dirp);
182*74a4d8c2SCharles.Forsyth return 1;
183*74a4d8c2SCharles.Forsyth }
184*74a4d8c2SCharles.Forsyth
185*74a4d8c2SCharles.Forsyth static void
atainit(void)186*74a4d8c2SCharles.Forsyth atainit(void)
187*74a4d8c2SCharles.Forsyth {
188*74a4d8c2SCharles.Forsyth Drive *dp;
189*74a4d8c2SCharles.Forsyth Controller *cp;
190*74a4d8c2SCharles.Forsyth uchar equip;
191*74a4d8c2SCharles.Forsyth int pcmslot;
192*74a4d8c2SCharles.Forsyth
193*74a4d8c2SCharles.Forsyth if (atac)
194*74a4d8c2SCharles.Forsyth return; /* already done */
195*74a4d8c2SCharles.Forsyth
196*74a4d8c2SCharles.Forsyth equip = 0x10; /* hard coded */
197*74a4d8c2SCharles.Forsyth
198*74a4d8c2SCharles.Forsyth print("ata init\n");
199*74a4d8c2SCharles.Forsyth cp = malloc(sizeof(*cp));
200*74a4d8c2SCharles.Forsyth if (!cp)
201*74a4d8c2SCharles.Forsyth error(Enomem);
202*74a4d8c2SCharles.Forsyth
203*74a4d8c2SCharles.Forsyth cp->port = Pbase;
204*74a4d8c2SCharles.Forsyth cp->irq = 14;
205*74a4d8c2SCharles.Forsyth
206*74a4d8c2SCharles.Forsyth if((pcmslot = pcmspecial("SunDisk", cp)) < 0) {
207*74a4d8c2SCharles.Forsyth print("No ATA card\n");
208*74a4d8c2SCharles.Forsyth free(cp);
209*74a4d8c2SCharles.Forsyth ataerr = Enoifc;
210*74a4d8c2SCharles.Forsyth return;
211*74a4d8c2SCharles.Forsyth }
212*74a4d8c2SCharles.Forsyth ata = malloc(2 * sizeof(*ata));
213*74a4d8c2SCharles.Forsyth if(ata == nil) {
214*74a4d8c2SCharles.Forsyth pcmspecialclose(pcmslot);
215*74a4d8c2SCharles.Forsyth free(cp);
216*74a4d8c2SCharles.Forsyth error(Enomem);
217*74a4d8c2SCharles.Forsyth }
218*74a4d8c2SCharles.Forsyth
219*74a4d8c2SCharles.Forsyth atac = cp;
220*74a4d8c2SCharles.Forsyth cp->buf = 0;
221*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
222*74a4d8c2SCharles.Forsyth cp->cmd = 0;
223*74a4d8c2SCharles.Forsyth cp->pbase = cp->port;
224*74a4d8c2SCharles.Forsyth pcmintrenable(pcmslot, ataintr, cp);
225*74a4d8c2SCharles.Forsyth
226*74a4d8c2SCharles.Forsyth dp = ata;
227*74a4d8c2SCharles.Forsyth if(equip & 0xf0){
228*74a4d8c2SCharles.Forsyth dp->drive = 0;
229*74a4d8c2SCharles.Forsyth dp->online = 0;
230*74a4d8c2SCharles.Forsyth dp->cp = cp;
231*74a4d8c2SCharles.Forsyth dp++;
232*74a4d8c2SCharles.Forsyth }
233*74a4d8c2SCharles.Forsyth if((equip & 0x0f)){
234*74a4d8c2SCharles.Forsyth dp->drive = 1;
235*74a4d8c2SCharles.Forsyth dp->online = 0;
236*74a4d8c2SCharles.Forsyth dp->cp = cp;
237*74a4d8c2SCharles.Forsyth dp++;
238*74a4d8c2SCharles.Forsyth }
239*74a4d8c2SCharles.Forsyth nhard = dp - ata;
240*74a4d8c2SCharles.Forsyth
241*74a4d8c2SCharles.Forsyth spindowntime = 1;
242*74a4d8c2SCharles.Forsyth }
243*74a4d8c2SCharles.Forsyth
244*74a4d8c2SCharles.Forsyth
245*74a4d8c2SCharles.Forsyth /*
246*74a4d8c2SCharles.Forsyth * Get the characteristics of each drive. Mark unresponsive ones
247*74a4d8c2SCharles.Forsyth * off line.
248*74a4d8c2SCharles.Forsyth */
249*74a4d8c2SCharles.Forsyth static Chan*
ataattach(char * spec)250*74a4d8c2SCharles.Forsyth ataattach(char *spec)
251*74a4d8c2SCharles.Forsyth {
252*74a4d8c2SCharles.Forsyth Drive *dp;
253*74a4d8c2SCharles.Forsyth
254*74a4d8c2SCharles.Forsyth atainit();
255*74a4d8c2SCharles.Forsyth if (!ata)
256*74a4d8c2SCharles.Forsyth error(ataerr ? ataerr : Enoifc);
257*74a4d8c2SCharles.Forsyth for(dp = ata; dp < &ata[nhard]; dp++){
258*74a4d8c2SCharles.Forsyth if(waserror()){
259*74a4d8c2SCharles.Forsyth dp->online = 0;
260*74a4d8c2SCharles.Forsyth qunlock(dp);
261*74a4d8c2SCharles.Forsyth continue;
262*74a4d8c2SCharles.Forsyth }
263*74a4d8c2SCharles.Forsyth qlock(dp);
264*74a4d8c2SCharles.Forsyth if(!dp->online){
265*74a4d8c2SCharles.Forsyth /*
266*74a4d8c2SCharles.Forsyth * Make sure ataclock() doesn't
267*74a4d8c2SCharles.Forsyth * interfere.
268*74a4d8c2SCharles.Forsyth */
269*74a4d8c2SCharles.Forsyth dp->usetime = m->ticks;
270*74a4d8c2SCharles.Forsyth ataparams(dp);
271*74a4d8c2SCharles.Forsyth dp->online = 1;
272*74a4d8c2SCharles.Forsyth atasetbuf(dp, 1);
273*74a4d8c2SCharles.Forsyth }
274*74a4d8c2SCharles.Forsyth
275*74a4d8c2SCharles.Forsyth /*
276*74a4d8c2SCharles.Forsyth * read Plan 9 partition table
277*74a4d8c2SCharles.Forsyth */
278*74a4d8c2SCharles.Forsyth atapart(dp);
279*74a4d8c2SCharles.Forsyth qunlock(dp);
280*74a4d8c2SCharles.Forsyth poperror();
281*74a4d8c2SCharles.Forsyth }
282*74a4d8c2SCharles.Forsyth return devattach('H', spec);
283*74a4d8c2SCharles.Forsyth }
284*74a4d8c2SCharles.Forsyth
285*74a4d8c2SCharles.Forsyth static int
atawalk(Chan * c,char * name)286*74a4d8c2SCharles.Forsyth atawalk(Chan *c, char *name)
287*74a4d8c2SCharles.Forsyth {
288*74a4d8c2SCharles.Forsyth return devwalk(c, name, 0, 0, atagen);
289*74a4d8c2SCharles.Forsyth }
290*74a4d8c2SCharles.Forsyth
291*74a4d8c2SCharles.Forsyth static void
atastat(Chan * c,char * dp)292*74a4d8c2SCharles.Forsyth atastat(Chan *c, char *dp)
293*74a4d8c2SCharles.Forsyth {
294*74a4d8c2SCharles.Forsyth devstat(c, dp, 0, 0, atagen);
295*74a4d8c2SCharles.Forsyth }
296*74a4d8c2SCharles.Forsyth
297*74a4d8c2SCharles.Forsyth static Chan*
ataopen(Chan * c,int omode)298*74a4d8c2SCharles.Forsyth ataopen(Chan *c, int omode)
299*74a4d8c2SCharles.Forsyth {
300*74a4d8c2SCharles.Forsyth return devopen(c, omode, 0, 0, atagen);
301*74a4d8c2SCharles.Forsyth }
302*74a4d8c2SCharles.Forsyth
303*74a4d8c2SCharles.Forsyth static void
ataclose(Chan * c)304*74a4d8c2SCharles.Forsyth ataclose(Chan *c)
305*74a4d8c2SCharles.Forsyth {
306*74a4d8c2SCharles.Forsyth Drive *d;
307*74a4d8c2SCharles.Forsyth Partition *p;
308*74a4d8c2SCharles.Forsyth
309*74a4d8c2SCharles.Forsyth if(c->mode != OWRITE && c->mode != ORDWR)
310*74a4d8c2SCharles.Forsyth return;
311*74a4d8c2SCharles.Forsyth
312*74a4d8c2SCharles.Forsyth d = &ata[DRIVE(c->qid.path)];
313*74a4d8c2SCharles.Forsyth p = &d->p[PART(c->qid.path)];
314*74a4d8c2SCharles.Forsyth if(strcmp(p->name, "partition") != 0)
315*74a4d8c2SCharles.Forsyth return;
316*74a4d8c2SCharles.Forsyth
317*74a4d8c2SCharles.Forsyth if(waserror()){
318*74a4d8c2SCharles.Forsyth qunlock(d);
319*74a4d8c2SCharles.Forsyth nexterror();
320*74a4d8c2SCharles.Forsyth }
321*74a4d8c2SCharles.Forsyth qlock(d);
322*74a4d8c2SCharles.Forsyth atapart(d);
323*74a4d8c2SCharles.Forsyth qunlock(d);
324*74a4d8c2SCharles.Forsyth poperror();
325*74a4d8c2SCharles.Forsyth }
326*74a4d8c2SCharles.Forsyth
327*74a4d8c2SCharles.Forsyth static long
ataread(Chan * c,void * a,long n,vlong offset)328*74a4d8c2SCharles.Forsyth ataread(Chan *c, void *a, long n, vlong offset)
329*74a4d8c2SCharles.Forsyth {
330*74a4d8c2SCharles.Forsyth Drive *dp;
331*74a4d8c2SCharles.Forsyth long rv, i;
332*74a4d8c2SCharles.Forsyth int skip;
333*74a4d8c2SCharles.Forsyth uchar *aa = a;
334*74a4d8c2SCharles.Forsyth Partition *pp;
335*74a4d8c2SCharles.Forsyth char *buf;
336*74a4d8c2SCharles.Forsyth
337*74a4d8c2SCharles.Forsyth if(c->qid.path == CHDIR)
338*74a4d8c2SCharles.Forsyth return devdirread(c, a, n, 0, 0, atagen);
339*74a4d8c2SCharles.Forsyth
340*74a4d8c2SCharles.Forsyth buf = smalloc(Maxxfer);
341*74a4d8c2SCharles.Forsyth if(waserror()){
342*74a4d8c2SCharles.Forsyth free(buf);
343*74a4d8c2SCharles.Forsyth nexterror();
344*74a4d8c2SCharles.Forsyth }
345*74a4d8c2SCharles.Forsyth
346*74a4d8c2SCharles.Forsyth dp = &ata[DRIVE(c->qid.path)];
347*74a4d8c2SCharles.Forsyth pp = &dp->p[PART(c->qid.path)];
348*74a4d8c2SCharles.Forsyth
349*74a4d8c2SCharles.Forsyth skip = offset % dp->bytes;
350*74a4d8c2SCharles.Forsyth for(rv = 0; rv < n; rv += i){
351*74a4d8c2SCharles.Forsyth i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf);
352*74a4d8c2SCharles.Forsyth if(i == 0)
353*74a4d8c2SCharles.Forsyth break;
354*74a4d8c2SCharles.Forsyth i -= skip;
355*74a4d8c2SCharles.Forsyth if(i > n - rv)
356*74a4d8c2SCharles.Forsyth i = n - rv;
357*74a4d8c2SCharles.Forsyth memmove(aa+rv, buf + skip, i);
358*74a4d8c2SCharles.Forsyth skip = 0;
359*74a4d8c2SCharles.Forsyth }
360*74a4d8c2SCharles.Forsyth
361*74a4d8c2SCharles.Forsyth free(buf);
362*74a4d8c2SCharles.Forsyth poperror();
363*74a4d8c2SCharles.Forsyth
364*74a4d8c2SCharles.Forsyth return rv;
365*74a4d8c2SCharles.Forsyth }
366*74a4d8c2SCharles.Forsyth
367*74a4d8c2SCharles.Forsyth static long
atawrite(Chan * c,void * a,long n,vlong offset)368*74a4d8c2SCharles.Forsyth atawrite(Chan *c, void *a, long n, vlong offset)
369*74a4d8c2SCharles.Forsyth {
370*74a4d8c2SCharles.Forsyth Drive *dp;
371*74a4d8c2SCharles.Forsyth long rv, i, partial;
372*74a4d8c2SCharles.Forsyth uchar *aa = a;
373*74a4d8c2SCharles.Forsyth Partition *pp;
374*74a4d8c2SCharles.Forsyth char *buf;
375*74a4d8c2SCharles.Forsyth
376*74a4d8c2SCharles.Forsyth if(c->qid.path == CHDIR)
377*74a4d8c2SCharles.Forsyth error(Eisdir);
378*74a4d8c2SCharles.Forsyth
379*74a4d8c2SCharles.Forsyth dp = &ata[DRIVE(c->qid.path)];
380*74a4d8c2SCharles.Forsyth pp = &dp->p[PART(c->qid.path)];
381*74a4d8c2SCharles.Forsyth buf = smalloc(Maxxfer);
382*74a4d8c2SCharles.Forsyth if(waserror()){
383*74a4d8c2SCharles.Forsyth free(buf);
384*74a4d8c2SCharles.Forsyth nexterror();
385*74a4d8c2SCharles.Forsyth }
386*74a4d8c2SCharles.Forsyth
387*74a4d8c2SCharles.Forsyth /*
388*74a4d8c2SCharles.Forsyth * if not starting on a sector boundary,
389*74a4d8c2SCharles.Forsyth * read in the first sector before writing
390*74a4d8c2SCharles.Forsyth * it out.
391*74a4d8c2SCharles.Forsyth */
392*74a4d8c2SCharles.Forsyth partial = offset % dp->bytes;
393*74a4d8c2SCharles.Forsyth if(partial){
394*74a4d8c2SCharles.Forsyth ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf);
395*74a4d8c2SCharles.Forsyth if(partial+n > dp->bytes)
396*74a4d8c2SCharles.Forsyth rv = dp->bytes - partial;
397*74a4d8c2SCharles.Forsyth else
398*74a4d8c2SCharles.Forsyth rv = n;
399*74a4d8c2SCharles.Forsyth memmove(buf+partial, aa, rv);
400*74a4d8c2SCharles.Forsyth ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf);
401*74a4d8c2SCharles.Forsyth } else
402*74a4d8c2SCharles.Forsyth rv = 0;
403*74a4d8c2SCharles.Forsyth
404*74a4d8c2SCharles.Forsyth /*
405*74a4d8c2SCharles.Forsyth * write out the full sectors
406*74a4d8c2SCharles.Forsyth */
407*74a4d8c2SCharles.Forsyth partial = (n - rv) % dp->bytes;
408*74a4d8c2SCharles.Forsyth n -= partial;
409*74a4d8c2SCharles.Forsyth for(; rv < n; rv += i){
410*74a4d8c2SCharles.Forsyth i = n - rv;
411*74a4d8c2SCharles.Forsyth if(i > Maxxfer)
412*74a4d8c2SCharles.Forsyth i = Maxxfer;
413*74a4d8c2SCharles.Forsyth memmove(buf, aa+rv, i);
414*74a4d8c2SCharles.Forsyth i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf);
415*74a4d8c2SCharles.Forsyth if(i == 0)
416*74a4d8c2SCharles.Forsyth break;
417*74a4d8c2SCharles.Forsyth }
418*74a4d8c2SCharles.Forsyth
419*74a4d8c2SCharles.Forsyth /*
420*74a4d8c2SCharles.Forsyth * if not ending on a sector boundary,
421*74a4d8c2SCharles.Forsyth * read in the last sector before writing
422*74a4d8c2SCharles.Forsyth * it out.
423*74a4d8c2SCharles.Forsyth */
424*74a4d8c2SCharles.Forsyth if(partial){
425*74a4d8c2SCharles.Forsyth ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf);
426*74a4d8c2SCharles.Forsyth memmove(buf, aa+rv, partial);
427*74a4d8c2SCharles.Forsyth ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf);
428*74a4d8c2SCharles.Forsyth rv += partial;
429*74a4d8c2SCharles.Forsyth }
430*74a4d8c2SCharles.Forsyth
431*74a4d8c2SCharles.Forsyth free(buf);
432*74a4d8c2SCharles.Forsyth poperror();
433*74a4d8c2SCharles.Forsyth
434*74a4d8c2SCharles.Forsyth return rv;
435*74a4d8c2SCharles.Forsyth }
436*74a4d8c2SCharles.Forsyth
437*74a4d8c2SCharles.Forsyth /*
438*74a4d8c2SCharles.Forsyth * did an interrupt happen?
439*74a4d8c2SCharles.Forsyth */
440*74a4d8c2SCharles.Forsyth static int
cmddone(void * a)441*74a4d8c2SCharles.Forsyth cmddone(void *a)
442*74a4d8c2SCharles.Forsyth {
443*74a4d8c2SCharles.Forsyth Controller *cp = a;
444*74a4d8c2SCharles.Forsyth
445*74a4d8c2SCharles.Forsyth return cp->cmd == 0;
446*74a4d8c2SCharles.Forsyth }
447*74a4d8c2SCharles.Forsyth
448*74a4d8c2SCharles.Forsyth /*
449*74a4d8c2SCharles.Forsyth * Wait for the controller to be ready to accept a command.
450*74a4d8c2SCharles.Forsyth * This is protected from intereference by ataclock() by
451*74a4d8c2SCharles.Forsyth * setting dp->usetime before it is called.
452*74a4d8c2SCharles.Forsyth */
453*74a4d8c2SCharles.Forsyth static void
cmdreadywait(Drive * dp)454*74a4d8c2SCharles.Forsyth cmdreadywait(Drive *dp)
455*74a4d8c2SCharles.Forsyth {
456*74a4d8c2SCharles.Forsyth long start;
457*74a4d8c2SCharles.Forsyth int period;
458*74a4d8c2SCharles.Forsyth Controller *cp = dp->cp;
459*74a4d8c2SCharles.Forsyth
460*74a4d8c2SCharles.Forsyth /* give it 2 seconds to spin down and up */
461*74a4d8c2SCharles.Forsyth if(dp->state == Sspinning)
462*74a4d8c2SCharles.Forsyth period = 10;
463*74a4d8c2SCharles.Forsyth else
464*74a4d8c2SCharles.Forsyth period = 2000;
465*74a4d8c2SCharles.Forsyth
466*74a4d8c2SCharles.Forsyth start = m->ticks;
467*74a4d8c2SCharles.Forsyth while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready)
468*74a4d8c2SCharles.Forsyth if(TK2MS(m->ticks - start) > period){
469*74a4d8c2SCharles.Forsyth DPRINT("cmdreadywait failed\n");
470*74a4d8c2SCharles.Forsyth error(Eio);
471*74a4d8c2SCharles.Forsyth }
472*74a4d8c2SCharles.Forsyth }
473*74a4d8c2SCharles.Forsyth
474*74a4d8c2SCharles.Forsyth static void
atarepl(Drive * dp,long bblk)475*74a4d8c2SCharles.Forsyth atarepl(Drive *dp, long bblk)
476*74a4d8c2SCharles.Forsyth {
477*74a4d8c2SCharles.Forsyth int i;
478*74a4d8c2SCharles.Forsyth
479*74a4d8c2SCharles.Forsyth if(dp->repl.p == 0)
480*74a4d8c2SCharles.Forsyth return;
481*74a4d8c2SCharles.Forsyth for(i = 0; i < dp->repl.nrepl; i++){
482*74a4d8c2SCharles.Forsyth if(dp->repl.blk[i] == bblk)
483*74a4d8c2SCharles.Forsyth DPRINT("found bblk %ld at offset %ld\n", bblk, i);
484*74a4d8c2SCharles.Forsyth }
485*74a4d8c2SCharles.Forsyth }
486*74a4d8c2SCharles.Forsyth
487*74a4d8c2SCharles.Forsyth static void
atasleep(Controller * cp,int ms)488*74a4d8c2SCharles.Forsyth atasleep(Controller *cp, int ms)
489*74a4d8c2SCharles.Forsyth {
490*74a4d8c2SCharles.Forsyth tsleep(&cp->r, cmddone, cp, ms);
491*74a4d8c2SCharles.Forsyth if(cp->cmd && cp->cmd != Cident2){
492*74a4d8c2SCharles.Forsyth DPRINT("ata: cmd 0x%uX timeout, status=%lux\n",
493*74a4d8c2SCharles.Forsyth cp->cmd, inb(cp->pbase+Pstatus));
494*74a4d8c2SCharles.Forsyth error("ata drive timeout");
495*74a4d8c2SCharles.Forsyth }
496*74a4d8c2SCharles.Forsyth }
497*74a4d8c2SCharles.Forsyth
498*74a4d8c2SCharles.Forsyth /*
499*74a4d8c2SCharles.Forsyth * transfer a number of sectors. ataintr will perform all the iterative
500*74a4d8c2SCharles.Forsyth * parts.
501*74a4d8c2SCharles.Forsyth */
502*74a4d8c2SCharles.Forsyth static long
ataxfer(Drive * dp,Partition * pp,int cmd,long start,long len,char * buf)503*74a4d8c2SCharles.Forsyth ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf)
504*74a4d8c2SCharles.Forsyth {
505*74a4d8c2SCharles.Forsyth Controller *cp;
506*74a4d8c2SCharles.Forsyth long lblk;
507*74a4d8c2SCharles.Forsyth int cyl, sec, head;
508*74a4d8c2SCharles.Forsyth int loop, stat;
509*74a4d8c2SCharles.Forsyth
510*74a4d8c2SCharles.Forsyth if(dp->online == 0)
511*74a4d8c2SCharles.Forsyth error(Eio);
512*74a4d8c2SCharles.Forsyth
513*74a4d8c2SCharles.Forsyth /*
514*74a4d8c2SCharles.Forsyth * cut transfer size down to disk buffer size
515*74a4d8c2SCharles.Forsyth */
516*74a4d8c2SCharles.Forsyth start = start / dp->bytes;
517*74a4d8c2SCharles.Forsyth if(len > Maxxfer)
518*74a4d8c2SCharles.Forsyth len = Maxxfer;
519*74a4d8c2SCharles.Forsyth len = (len + dp->bytes - 1) / dp->bytes;
520*74a4d8c2SCharles.Forsyth if(len == 0)
521*74a4d8c2SCharles.Forsyth return 0;
522*74a4d8c2SCharles.Forsyth
523*74a4d8c2SCharles.Forsyth /*
524*74a4d8c2SCharles.Forsyth * calculate physical address
525*74a4d8c2SCharles.Forsyth */
526*74a4d8c2SCharles.Forsyth lblk = start + pp->start;
527*74a4d8c2SCharles.Forsyth if(lblk >= pp->end)
528*74a4d8c2SCharles.Forsyth return 0;
529*74a4d8c2SCharles.Forsyth if(lblk+len > pp->end)
530*74a4d8c2SCharles.Forsyth len = pp->end - lblk;
531*74a4d8c2SCharles.Forsyth if(dp->lba){
532*74a4d8c2SCharles.Forsyth sec = lblk & 0xff;
533*74a4d8c2SCharles.Forsyth cyl = (lblk>>8) & 0xffff;
534*74a4d8c2SCharles.Forsyth head = (lblk>>24) & 0xf;
535*74a4d8c2SCharles.Forsyth } else {
536*74a4d8c2SCharles.Forsyth cyl = lblk/(dp->sectors*dp->heads);
537*74a4d8c2SCharles.Forsyth sec = (lblk % dp->sectors) + 1;
538*74a4d8c2SCharles.Forsyth head = ((lblk/dp->sectors) % dp->heads);
539*74a4d8c2SCharles.Forsyth }
540*74a4d8c2SCharles.Forsyth
541*74a4d8c2SCharles.Forsyth DPRINT("<%s %d>", (cmd == Cwrite) ? "W" : "R", lblk);
542*74a4d8c2SCharles.Forsyth cp = dp->cp;
543*74a4d8c2SCharles.Forsyth qlock(cp);
544*74a4d8c2SCharles.Forsyth if(waserror()){
545*74a4d8c2SCharles.Forsyth cp->buf = 0;
546*74a4d8c2SCharles.Forsyth qunlock(cp);
547*74a4d8c2SCharles.Forsyth nexterror();
548*74a4d8c2SCharles.Forsyth }
549*74a4d8c2SCharles.Forsyth
550*74a4d8c2SCharles.Forsyth /*
551*74a4d8c2SCharles.Forsyth * Make sure hardclock() doesn't
552*74a4d8c2SCharles.Forsyth * interfere.
553*74a4d8c2SCharles.Forsyth */
554*74a4d8c2SCharles.Forsyth dp->usetime = m->ticks;
555*74a4d8c2SCharles.Forsyth cmdreadywait(dp);
556*74a4d8c2SCharles.Forsyth
557*74a4d8c2SCharles.Forsyth ilock(&cp->reglock);
558*74a4d8c2SCharles.Forsyth cp->sofar = 0;
559*74a4d8c2SCharles.Forsyth cp->buf = buf;
560*74a4d8c2SCharles.Forsyth cp->nsecs = len;
561*74a4d8c2SCharles.Forsyth cp->cmd = cmd;
562*74a4d8c2SCharles.Forsyth cp->dp = dp;
563*74a4d8c2SCharles.Forsyth cp->status = 0;
564*74a4d8c2SCharles.Forsyth
565*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcount, cp->nsecs);
566*74a4d8c2SCharles.Forsyth outb(cp->pbase+Psector, sec);
567*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head);
568*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcyllsb, cyl);
569*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcylmsb, cyl>>8);
570*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcmd, cmd);
571*74a4d8c2SCharles.Forsyth
572*74a4d8c2SCharles.Forsyth if(cmd == Cwrite){
573*74a4d8c2SCharles.Forsyth loop = 0;
574*74a4d8c2SCharles.Forsyth microdelay(1);
575*74a4d8c2SCharles.Forsyth while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0)
576*74a4d8c2SCharles.Forsyth if(++loop > 10000)
577*74a4d8c2SCharles.Forsyth panic("ataxfer");
578*74a4d8c2SCharles.Forsyth outss(cp->pbase+Pdata, cp->buf, dp->bytes/2);
579*74a4d8c2SCharles.Forsyth } else
580*74a4d8c2SCharles.Forsyth stat = 0;
581*74a4d8c2SCharles.Forsyth iunlock(&cp->reglock);
582*74a4d8c2SCharles.Forsyth
583*74a4d8c2SCharles.Forsyth if(stat & Serr)
584*74a4d8c2SCharles.Forsyth error(Eio);
585*74a4d8c2SCharles.Forsyth
586*74a4d8c2SCharles.Forsyth /*
587*74a4d8c2SCharles.Forsyth * wait for command to complete. if we get a note,
588*74a4d8c2SCharles.Forsyth * remember it but keep waiting to let the disk finish
589*74a4d8c2SCharles.Forsyth * the current command.
590*74a4d8c2SCharles.Forsyth */
591*74a4d8c2SCharles.Forsyth loop = 0;
592*74a4d8c2SCharles.Forsyth while(waserror()){
593*74a4d8c2SCharles.Forsyth DPRINT("interrupted ataxfer\n");
594*74a4d8c2SCharles.Forsyth if(loop++ > 10){
595*74a4d8c2SCharles.Forsyth print("ata disk error\n");
596*74a4d8c2SCharles.Forsyth nexterror();
597*74a4d8c2SCharles.Forsyth }
598*74a4d8c2SCharles.Forsyth }
599*74a4d8c2SCharles.Forsyth atasleep(cp, 3000);
600*74a4d8c2SCharles.Forsyth dp->state = Sspinning;
601*74a4d8c2SCharles.Forsyth dp->usetime = m->ticks;
602*74a4d8c2SCharles.Forsyth poperror();
603*74a4d8c2SCharles.Forsyth if(loop)
604*74a4d8c2SCharles.Forsyth nexterror();
605*74a4d8c2SCharles.Forsyth
606*74a4d8c2SCharles.Forsyth if(cp->status & Serr){
607*74a4d8c2SCharles.Forsyth DPRINT("hd%d err: lblk %ld status %lux, err %lux\n",
608*74a4d8c2SCharles.Forsyth dp-ata, lblk, cp->status, cp->error);
609*74a4d8c2SCharles.Forsyth DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head);
610*74a4d8c2SCharles.Forsyth DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar);
611*74a4d8c2SCharles.Forsyth atarepl(dp, lblk+cp->sofar);
612*74a4d8c2SCharles.Forsyth error(Eio);
613*74a4d8c2SCharles.Forsyth }
614*74a4d8c2SCharles.Forsyth cp->buf = 0;
615*74a4d8c2SCharles.Forsyth len = cp->sofar*dp->bytes;
616*74a4d8c2SCharles.Forsyth qunlock(cp);
617*74a4d8c2SCharles.Forsyth poperror();
618*74a4d8c2SCharles.Forsyth
619*74a4d8c2SCharles.Forsyth return len;
620*74a4d8c2SCharles.Forsyth }
621*74a4d8c2SCharles.Forsyth
622*74a4d8c2SCharles.Forsyth /*
623*74a4d8c2SCharles.Forsyth * set read ahead mode
624*74a4d8c2SCharles.Forsyth */
625*74a4d8c2SCharles.Forsyth static void
atasetbuf(Drive * dp,int on)626*74a4d8c2SCharles.Forsyth atasetbuf(Drive *dp, int on)
627*74a4d8c2SCharles.Forsyth {
628*74a4d8c2SCharles.Forsyth Controller *cp = dp->cp;
629*74a4d8c2SCharles.Forsyth
630*74a4d8c2SCharles.Forsyth qlock(cp);
631*74a4d8c2SCharles.Forsyth if(waserror()){
632*74a4d8c2SCharles.Forsyth qunlock(cp);
633*74a4d8c2SCharles.Forsyth nexterror();
634*74a4d8c2SCharles.Forsyth }
635*74a4d8c2SCharles.Forsyth
636*74a4d8c2SCharles.Forsyth cmdreadywait(dp);
637*74a4d8c2SCharles.Forsyth
638*74a4d8c2SCharles.Forsyth ilock(&cp->reglock);
639*74a4d8c2SCharles.Forsyth cp->cmd = Csetbuf;
640*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */
641*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4));
642*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcmd, Csetbuf);
643*74a4d8c2SCharles.Forsyth iunlock(&cp->reglock);
644*74a4d8c2SCharles.Forsyth
645*74a4d8c2SCharles.Forsyth atasleep(cp, 5000);
646*74a4d8c2SCharles.Forsyth
647*74a4d8c2SCharles.Forsyth /* if(cp->status & Serr)
648*74a4d8c2SCharles.Forsyth DPRINT("hd%d setbuf err: status %lux, err %lux\n",
649*74a4d8c2SCharles.Forsyth dp-ata, cp->status, cp->error);/**/
650*74a4d8c2SCharles.Forsyth
651*74a4d8c2SCharles.Forsyth poperror();
652*74a4d8c2SCharles.Forsyth qunlock(cp);
653*74a4d8c2SCharles.Forsyth }
654*74a4d8c2SCharles.Forsyth
655*74a4d8c2SCharles.Forsyth /*
656*74a4d8c2SCharles.Forsyth * ident sector from drive. this is from ANSI X3.221-1994
657*74a4d8c2SCharles.Forsyth */
658*74a4d8c2SCharles.Forsyth struct Ident
659*74a4d8c2SCharles.Forsyth {
660*74a4d8c2SCharles.Forsyth ushort config; /* general configuration info */
661*74a4d8c2SCharles.Forsyth ushort cyls; /* # of cylinders (default) */
662*74a4d8c2SCharles.Forsyth ushort reserved0;
663*74a4d8c2SCharles.Forsyth ushort heads; /* # of heads (default) */
664*74a4d8c2SCharles.Forsyth ushort b2t; /* unformatted bytes/track */
665*74a4d8c2SCharles.Forsyth ushort b2s; /* unformated bytes/sector */
666*74a4d8c2SCharles.Forsyth ushort s2t; /* sectors/track (default) */
667*74a4d8c2SCharles.Forsyth ushort reserved1[3];
668*74a4d8c2SCharles.Forsyth /* 10 */
669*74a4d8c2SCharles.Forsyth ushort serial[10]; /* serial number */
670*74a4d8c2SCharles.Forsyth ushort type; /* buffer type */
671*74a4d8c2SCharles.Forsyth ushort bsize; /* buffer size/512 */
672*74a4d8c2SCharles.Forsyth ushort ecc; /* ecc bytes returned by read long */
673*74a4d8c2SCharles.Forsyth ushort firm[4]; /* firmware revision */
674*74a4d8c2SCharles.Forsyth ushort model[20]; /* model number */
675*74a4d8c2SCharles.Forsyth /* 47 */
676*74a4d8c2SCharles.Forsyth ushort s2i; /* number of sectors/interrupt */
677*74a4d8c2SCharles.Forsyth ushort dwtf; /* double word transfer flag */
678*74a4d8c2SCharles.Forsyth ushort capabilities;
679*74a4d8c2SCharles.Forsyth ushort reserved2;
680*74a4d8c2SCharles.Forsyth ushort piomode;
681*74a4d8c2SCharles.Forsyth ushort dmamode;
682*74a4d8c2SCharles.Forsyth ushort cvalid; /* (cvald&1) if next 4 words are valid */
683*74a4d8c2SCharles.Forsyth ushort ccyls; /* current # cylinders */
684*74a4d8c2SCharles.Forsyth ushort cheads; /* current # heads */
685*74a4d8c2SCharles.Forsyth ushort cs2t; /* current sectors/track */
686*74a4d8c2SCharles.Forsyth ushort ccap[2]; /* current capacity in sectors */
687*74a4d8c2SCharles.Forsyth ushort cs2i; /* current number of sectors/interrupt */
688*74a4d8c2SCharles.Forsyth /* 60 */
689*74a4d8c2SCharles.Forsyth ushort lbasecs[2]; /* # LBA user addressable sectors */
690*74a4d8c2SCharles.Forsyth ushort dmasingle;
691*74a4d8c2SCharles.Forsyth ushort dmadouble;
692*74a4d8c2SCharles.Forsyth /* 64 */
693*74a4d8c2SCharles.Forsyth ushort reserved3[64];
694*74a4d8c2SCharles.Forsyth ushort vendor[32]; /* vendor specific */
695*74a4d8c2SCharles.Forsyth ushort reserved4[96];
696*74a4d8c2SCharles.Forsyth };
697*74a4d8c2SCharles.Forsyth
698*74a4d8c2SCharles.Forsyth /*
699*74a4d8c2SCharles.Forsyth * get parameters from the drive
700*74a4d8c2SCharles.Forsyth */
701*74a4d8c2SCharles.Forsyth static void
ataident(Drive * dp)702*74a4d8c2SCharles.Forsyth ataident(Drive *dp)
703*74a4d8c2SCharles.Forsyth {
704*74a4d8c2SCharles.Forsyth Controller *cp;
705*74a4d8c2SCharles.Forsyth char *buf;
706*74a4d8c2SCharles.Forsyth Ident *ip;
707*74a4d8c2SCharles.Forsyth char id[21];
708*74a4d8c2SCharles.Forsyth
709*74a4d8c2SCharles.Forsyth cp = dp->cp;
710*74a4d8c2SCharles.Forsyth buf = smalloc(Maxxfer);
711*74a4d8c2SCharles.Forsyth qlock(cp);
712*74a4d8c2SCharles.Forsyth if(waserror()){
713*74a4d8c2SCharles.Forsyth cp->buf = 0;
714*74a4d8c2SCharles.Forsyth qunlock(cp);
715*74a4d8c2SCharles.Forsyth free(buf);
716*74a4d8c2SCharles.Forsyth nexterror();
717*74a4d8c2SCharles.Forsyth }
718*74a4d8c2SCharles.Forsyth
719*74a4d8c2SCharles.Forsyth cmdreadywait(dp);
720*74a4d8c2SCharles.Forsyth
721*74a4d8c2SCharles.Forsyth ilock(&cp->reglock);
722*74a4d8c2SCharles.Forsyth cp->nsecs = 1;
723*74a4d8c2SCharles.Forsyth cp->sofar = 0;
724*74a4d8c2SCharles.Forsyth cp->cmd = Cident;
725*74a4d8c2SCharles.Forsyth cp->dp = dp;
726*74a4d8c2SCharles.Forsyth cp->buf = buf;
727*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4));
728*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcmd, Cident);
729*74a4d8c2SCharles.Forsyth iunlock(&cp->reglock);
730*74a4d8c2SCharles.Forsyth
731*74a4d8c2SCharles.Forsyth atasleep(cp, 5000);
732*74a4d8c2SCharles.Forsyth if(cp->status & Serr){
733*74a4d8c2SCharles.Forsyth DPRINT("bad disk ident status\n");
734*74a4d8c2SCharles.Forsyth error(Eio);
735*74a4d8c2SCharles.Forsyth }
736*74a4d8c2SCharles.Forsyth ip = (Ident*)buf;
737*74a4d8c2SCharles.Forsyth
738*74a4d8c2SCharles.Forsyth /*
739*74a4d8c2SCharles.Forsyth * this function appears to respond with an extra interrupt after
740*74a4d8c2SCharles.Forsyth * the ident information is read, except on the safari. The following
741*74a4d8c2SCharles.Forsyth * delay gives this extra interrupt a chance to happen while we are quiet.
742*74a4d8c2SCharles.Forsyth * Otherwise, the interrupt may come during a subsequent read or write,
743*74a4d8c2SCharles.Forsyth * causing a panic and much confusion.
744*74a4d8c2SCharles.Forsyth */
745*74a4d8c2SCharles.Forsyth if (cp->cmd == Cident2)
746*74a4d8c2SCharles.Forsyth tsleep(&cp->r, return0, 0, 10);
747*74a4d8c2SCharles.Forsyth
748*74a4d8c2SCharles.Forsyth memmove(id, ip->model, sizeof(id)-1);
749*74a4d8c2SCharles.Forsyth id[sizeof(id)-1] = 0;
750*74a4d8c2SCharles.Forsyth
751*74a4d8c2SCharles.Forsyth if(ip->capabilities & (1<<9)){
752*74a4d8c2SCharles.Forsyth dp->lba = 1;
753*74a4d8c2SCharles.Forsyth dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16);
754*74a4d8c2SCharles.Forsyth dp->cap = dp->bytes * dp->sectors;
755*74a4d8c2SCharles.Forsyth /*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/
756*74a4d8c2SCharles.Forsyth } else {
757*74a4d8c2SCharles.Forsyth dp->lba = 0;
758*74a4d8c2SCharles.Forsyth
759*74a4d8c2SCharles.Forsyth /* use default (unformatted) settings */
760*74a4d8c2SCharles.Forsyth dp->cyl = ip->cyls;
761*74a4d8c2SCharles.Forsyth dp->heads = ip->heads;
762*74a4d8c2SCharles.Forsyth dp->sectors = ip->s2t;
763*74a4d8c2SCharles.Forsyth /*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive,
764*74a4d8c2SCharles.Forsyth id, dp->cyl, dp->heads, dp->sectors);/**/
765*74a4d8c2SCharles.Forsyth
766*74a4d8c2SCharles.Forsyth if(ip->cvalid&(1<<0)){
767*74a4d8c2SCharles.Forsyth /* use current settings */
768*74a4d8c2SCharles.Forsyth dp->cyl = ip->ccyls;
769*74a4d8c2SCharles.Forsyth dp->heads = ip->cheads;
770*74a4d8c2SCharles.Forsyth dp->sectors = ip->cs2t;
771*74a4d8c2SCharles.Forsyth /*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/
772*74a4d8c2SCharles.Forsyth }
773*74a4d8c2SCharles.Forsyth dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
774*74a4d8c2SCharles.Forsyth }
775*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
776*74a4d8c2SCharles.Forsyth cp->cmd = 0;
777*74a4d8c2SCharles.Forsyth cp->buf = 0;
778*74a4d8c2SCharles.Forsyth free(buf);
779*74a4d8c2SCharles.Forsyth poperror();
780*74a4d8c2SCharles.Forsyth qunlock(cp);
781*74a4d8c2SCharles.Forsyth }
782*74a4d8c2SCharles.Forsyth
783*74a4d8c2SCharles.Forsyth /*
784*74a4d8c2SCharles.Forsyth * probe the given sector to see if it exists
785*74a4d8c2SCharles.Forsyth */
786*74a4d8c2SCharles.Forsyth static int
ataprobe(Drive * dp,int cyl,int sec,int head)787*74a4d8c2SCharles.Forsyth ataprobe(Drive *dp, int cyl, int sec, int head)
788*74a4d8c2SCharles.Forsyth {
789*74a4d8c2SCharles.Forsyth Controller *cp;
790*74a4d8c2SCharles.Forsyth char *buf;
791*74a4d8c2SCharles.Forsyth int rv;
792*74a4d8c2SCharles.Forsyth
793*74a4d8c2SCharles.Forsyth cp = dp->cp;
794*74a4d8c2SCharles.Forsyth buf = smalloc(Maxxfer);
795*74a4d8c2SCharles.Forsyth qlock(cp);
796*74a4d8c2SCharles.Forsyth if(waserror()){
797*74a4d8c2SCharles.Forsyth free(buf);
798*74a4d8c2SCharles.Forsyth qunlock(cp);
799*74a4d8c2SCharles.Forsyth nexterror();
800*74a4d8c2SCharles.Forsyth }
801*74a4d8c2SCharles.Forsyth
802*74a4d8c2SCharles.Forsyth cmdreadywait(dp);
803*74a4d8c2SCharles.Forsyth
804*74a4d8c2SCharles.Forsyth ilock(&cp->reglock);
805*74a4d8c2SCharles.Forsyth cp->cmd = Cread;
806*74a4d8c2SCharles.Forsyth cp->dp = dp;
807*74a4d8c2SCharles.Forsyth cp->status = 0;
808*74a4d8c2SCharles.Forsyth cp->nsecs = 1;
809*74a4d8c2SCharles.Forsyth cp->sofar = 0;
810*74a4d8c2SCharles.Forsyth
811*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcount, 1);
812*74a4d8c2SCharles.Forsyth outb(cp->pbase+Psector, sec+1);
813*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4));
814*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcyllsb, cyl);
815*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcylmsb, cyl>>8);
816*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcmd, Cread);
817*74a4d8c2SCharles.Forsyth iunlock(&cp->reglock);
818*74a4d8c2SCharles.Forsyth
819*74a4d8c2SCharles.Forsyth atasleep(cp, 5000);
820*74a4d8c2SCharles.Forsyth
821*74a4d8c2SCharles.Forsyth if(cp->status & Serr)
822*74a4d8c2SCharles.Forsyth rv = -1;
823*74a4d8c2SCharles.Forsyth else
824*74a4d8c2SCharles.Forsyth rv = 0;
825*74a4d8c2SCharles.Forsyth
826*74a4d8c2SCharles.Forsyth cp->buf = 0;
827*74a4d8c2SCharles.Forsyth free(buf);
828*74a4d8c2SCharles.Forsyth poperror();
829*74a4d8c2SCharles.Forsyth qunlock(cp);
830*74a4d8c2SCharles.Forsyth return rv;
831*74a4d8c2SCharles.Forsyth }
832*74a4d8c2SCharles.Forsyth
833*74a4d8c2SCharles.Forsyth /*
834*74a4d8c2SCharles.Forsyth * figure out the drive parameters
835*74a4d8c2SCharles.Forsyth */
836*74a4d8c2SCharles.Forsyth static void
ataparams(Drive * dp)837*74a4d8c2SCharles.Forsyth ataparams(Drive *dp)
838*74a4d8c2SCharles.Forsyth {
839*74a4d8c2SCharles.Forsyth int i, hi, lo;
840*74a4d8c2SCharles.Forsyth
841*74a4d8c2SCharles.Forsyth /*
842*74a4d8c2SCharles.Forsyth * first try the easy way, ask the drive and make sure it
843*74a4d8c2SCharles.Forsyth * isn't lying.
844*74a4d8c2SCharles.Forsyth */
845*74a4d8c2SCharles.Forsyth dp->bytes = 512;
846*74a4d8c2SCharles.Forsyth ataident(dp);
847*74a4d8c2SCharles.Forsyth if(dp->lba){
848*74a4d8c2SCharles.Forsyth i = dp->sectors - 1;
849*74a4d8c2SCharles.Forsyth if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0)
850*74a4d8c2SCharles.Forsyth return;
851*74a4d8c2SCharles.Forsyth } else {
852*74a4d8c2SCharles.Forsyth if(ataprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0)
853*74a4d8c2SCharles.Forsyth return;
854*74a4d8c2SCharles.Forsyth }
855*74a4d8c2SCharles.Forsyth
856*74a4d8c2SCharles.Forsyth /*
857*74a4d8c2SCharles.Forsyth * the drive lied, determine parameters by seeing which ones
858*74a4d8c2SCharles.Forsyth * work to read sectors.
859*74a4d8c2SCharles.Forsyth */
860*74a4d8c2SCharles.Forsyth dp->lba = 0;
861*74a4d8c2SCharles.Forsyth for(i = 0; i < 32; i++)
862*74a4d8c2SCharles.Forsyth if(ataprobe(dp, 0, 0, i) < 0)
863*74a4d8c2SCharles.Forsyth break;
864*74a4d8c2SCharles.Forsyth dp->heads = i;
865*74a4d8c2SCharles.Forsyth for(i = 0; i < 128; i++)
866*74a4d8c2SCharles.Forsyth if(ataprobe(dp, 0, i, 0) < 0)
867*74a4d8c2SCharles.Forsyth break;
868*74a4d8c2SCharles.Forsyth dp->sectors = i;
869*74a4d8c2SCharles.Forsyth for(i = 512; ; i += 512)
870*74a4d8c2SCharles.Forsyth if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
871*74a4d8c2SCharles.Forsyth break;
872*74a4d8c2SCharles.Forsyth lo = i - 512;
873*74a4d8c2SCharles.Forsyth hi = i;
874*74a4d8c2SCharles.Forsyth for(; hi-lo > 1;){
875*74a4d8c2SCharles.Forsyth i = lo + (hi - lo)/2;
876*74a4d8c2SCharles.Forsyth if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
877*74a4d8c2SCharles.Forsyth hi = i;
878*74a4d8c2SCharles.Forsyth else
879*74a4d8c2SCharles.Forsyth lo = i;
880*74a4d8c2SCharles.Forsyth }
881*74a4d8c2SCharles.Forsyth dp->cyl = lo + 1;
882*74a4d8c2SCharles.Forsyth dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
883*74a4d8c2SCharles.Forsyth }
884*74a4d8c2SCharles.Forsyth
885*74a4d8c2SCharles.Forsyth /*
886*74a4d8c2SCharles.Forsyth * Read block replacement table.
887*74a4d8c2SCharles.Forsyth * The table is just ascii block numbers.
888*74a4d8c2SCharles.Forsyth */
889*74a4d8c2SCharles.Forsyth static void
atareplinit(Drive * dp)890*74a4d8c2SCharles.Forsyth atareplinit(Drive *dp)
891*74a4d8c2SCharles.Forsyth {
892*74a4d8c2SCharles.Forsyth char *line[Nrepl+1];
893*74a4d8c2SCharles.Forsyth char *field[1];
894*74a4d8c2SCharles.Forsyth ulong n;
895*74a4d8c2SCharles.Forsyth int i;
896*74a4d8c2SCharles.Forsyth char *buf;
897*74a4d8c2SCharles.Forsyth
898*74a4d8c2SCharles.Forsyth /*
899*74a4d8c2SCharles.Forsyth * check the partition is big enough
900*74a4d8c2SCharles.Forsyth */
901*74a4d8c2SCharles.Forsyth if(dp->repl.p->end - dp->repl.p->start < Nrepl+1){
902*74a4d8c2SCharles.Forsyth dp->repl.p = 0;
903*74a4d8c2SCharles.Forsyth return;
904*74a4d8c2SCharles.Forsyth }
905*74a4d8c2SCharles.Forsyth
906*74a4d8c2SCharles.Forsyth buf = smalloc(Maxxfer);
907*74a4d8c2SCharles.Forsyth if(waserror()){
908*74a4d8c2SCharles.Forsyth free(buf);
909*74a4d8c2SCharles.Forsyth nexterror();
910*74a4d8c2SCharles.Forsyth }
911*74a4d8c2SCharles.Forsyth
912*74a4d8c2SCharles.Forsyth /*
913*74a4d8c2SCharles.Forsyth * read replacement table from disk, null terminate
914*74a4d8c2SCharles.Forsyth */
915*74a4d8c2SCharles.Forsyth ataxfer(dp, dp->repl.p, Cread, 0, dp->bytes, buf);
916*74a4d8c2SCharles.Forsyth buf[dp->bytes-1] = 0;
917*74a4d8c2SCharles.Forsyth
918*74a4d8c2SCharles.Forsyth /*
919*74a4d8c2SCharles.Forsyth * parse replacement table.
920*74a4d8c2SCharles.Forsyth */
921*74a4d8c2SCharles.Forsyth n = getfields(buf, line, Nrepl+1, 1, "\n");
922*74a4d8c2SCharles.Forsyth if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){
923*74a4d8c2SCharles.Forsyth dp->repl.p = 0;
924*74a4d8c2SCharles.Forsyth } else {
925*74a4d8c2SCharles.Forsyth for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){
926*74a4d8c2SCharles.Forsyth if(getfields(line[i], field, 1, 1, " ") != 1)
927*74a4d8c2SCharles.Forsyth break;
928*74a4d8c2SCharles.Forsyth dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0);
929*74a4d8c2SCharles.Forsyth if(dp->repl.blk[dp->repl.nrepl] <= 0)
930*74a4d8c2SCharles.Forsyth break;
931*74a4d8c2SCharles.Forsyth }
932*74a4d8c2SCharles.Forsyth }
933*74a4d8c2SCharles.Forsyth free(buf);
934*74a4d8c2SCharles.Forsyth poperror();
935*74a4d8c2SCharles.Forsyth }
936*74a4d8c2SCharles.Forsyth
937*74a4d8c2SCharles.Forsyth /*
938*74a4d8c2SCharles.Forsyth * read partition table. The partition table is just ascii strings.
939*74a4d8c2SCharles.Forsyth */
940*74a4d8c2SCharles.Forsyth static void
atapart(Drive * dp)941*74a4d8c2SCharles.Forsyth atapart(Drive *dp)
942*74a4d8c2SCharles.Forsyth {
943*74a4d8c2SCharles.Forsyth Partition *pp;
944*74a4d8c2SCharles.Forsyth char *line[Npart+1];
945*74a4d8c2SCharles.Forsyth char *field[3];
946*74a4d8c2SCharles.Forsyth ulong n;
947*74a4d8c2SCharles.Forsyth int i;
948*74a4d8c2SCharles.Forsyth char *buf;
949*74a4d8c2SCharles.Forsyth
950*74a4d8c2SCharles.Forsyth sprint(dp->vol, "hd%d", dp - ata);
951*74a4d8c2SCharles.Forsyth
952*74a4d8c2SCharles.Forsyth /*
953*74a4d8c2SCharles.Forsyth * we always have a partition for the whole disk
954*74a4d8c2SCharles.Forsyth * and one for the partition table
955*74a4d8c2SCharles.Forsyth */
956*74a4d8c2SCharles.Forsyth pp = &dp->p[0];
957*74a4d8c2SCharles.Forsyth strcpy(pp->name, "disk");
958*74a4d8c2SCharles.Forsyth pp->start = 0;
959*74a4d8c2SCharles.Forsyth pp->end = dp->cap / dp->bytes;
960*74a4d8c2SCharles.Forsyth pp++;
961*74a4d8c2SCharles.Forsyth strcpy(pp->name, "partition");
962*74a4d8c2SCharles.Forsyth pp->start = dp->p[0].end - 1;
963*74a4d8c2SCharles.Forsyth pp->end = dp->p[0].end;
964*74a4d8c2SCharles.Forsyth pp++;
965*74a4d8c2SCharles.Forsyth dp->npart = 2;
966*74a4d8c2SCharles.Forsyth
967*74a4d8c2SCharles.Forsyth /*
968*74a4d8c2SCharles.Forsyth * initialise the bad-block replacement info
969*74a4d8c2SCharles.Forsyth */
970*74a4d8c2SCharles.Forsyth dp->repl.p = 0;
971*74a4d8c2SCharles.Forsyth
972*74a4d8c2SCharles.Forsyth buf = smalloc(Maxxfer);
973*74a4d8c2SCharles.Forsyth if(waserror()){
974*74a4d8c2SCharles.Forsyth free(buf);
975*74a4d8c2SCharles.Forsyth nexterror();
976*74a4d8c2SCharles.Forsyth }
977*74a4d8c2SCharles.Forsyth
978*74a4d8c2SCharles.Forsyth /*
979*74a4d8c2SCharles.Forsyth * read last sector from disk, null terminate. This used
980*74a4d8c2SCharles.Forsyth * to be the sector we used for the partition tables.
981*74a4d8c2SCharles.Forsyth * However, this sector is special on some PC's so we've
982*74a4d8c2SCharles.Forsyth * started to use the second last sector as the partition
983*74a4d8c2SCharles.Forsyth * table instead. To avoid reconfiguring all our old systems
984*74a4d8c2SCharles.Forsyth * we first look to see if there is a valid partition
985*74a4d8c2SCharles.Forsyth * table in the last sector. If so, we use it. Otherwise
986*74a4d8c2SCharles.Forsyth * we switch to the second last.
987*74a4d8c2SCharles.Forsyth */
988*74a4d8c2SCharles.Forsyth ataxfer(dp, dp->p+1, Cread, 0, dp->bytes, buf);
989*74a4d8c2SCharles.Forsyth buf[dp->bytes-1] = 0;
990*74a4d8c2SCharles.Forsyth n = getfields(buf, line, Npart+1, 1, "\n");
991*74a4d8c2SCharles.Forsyth if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){
992*74a4d8c2SCharles.Forsyth dp->p[0].end--;
993*74a4d8c2SCharles.Forsyth dp->p[1].start--;
994*74a4d8c2SCharles.Forsyth dp->p[1].end--;
995*74a4d8c2SCharles.Forsyth ataxfer(dp, dp->p+1, Cread, 0, dp->bytes, buf);
996*74a4d8c2SCharles.Forsyth buf[dp->bytes-1] = 0;
997*74a4d8c2SCharles.Forsyth n = getfields(buf, line, Npart+1, 1, "\n");
998*74a4d8c2SCharles.Forsyth }
999*74a4d8c2SCharles.Forsyth
1000*74a4d8c2SCharles.Forsyth /*
1001*74a4d8c2SCharles.Forsyth * parse partition table.
1002*74a4d8c2SCharles.Forsyth */
1003*74a4d8c2SCharles.Forsyth if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
1004*74a4d8c2SCharles.Forsyth for(i = 1; i < n; i++){
1005*74a4d8c2SCharles.Forsyth switch(getfields(line[i], field, 3, 1, " ")) {
1006*74a4d8c2SCharles.Forsyth case 2:
1007*74a4d8c2SCharles.Forsyth if(strcmp(field[0], "unit") == 0)
1008*74a4d8c2SCharles.Forsyth strncpy(dp->vol, field[1], NAMELEN);
1009*74a4d8c2SCharles.Forsyth break;
1010*74a4d8c2SCharles.Forsyth case 3:
1011*74a4d8c2SCharles.Forsyth strncpy(pp->name, field[0], NAMELEN);
1012*74a4d8c2SCharles.Forsyth if(strncmp(pp->name, "repl", NAMELEN) == 0)
1013*74a4d8c2SCharles.Forsyth dp->repl.p = pp;
1014*74a4d8c2SCharles.Forsyth pp->start = strtoul(field[1], 0, 0);
1015*74a4d8c2SCharles.Forsyth pp->end = strtoul(field[2], 0, 0);
1016*74a4d8c2SCharles.Forsyth if(pp->start > pp->end || pp->end > dp->p[0].end)
1017*74a4d8c2SCharles.Forsyth break;
1018*74a4d8c2SCharles.Forsyth dp->npart++;
1019*74a4d8c2SCharles.Forsyth pp++;
1020*74a4d8c2SCharles.Forsyth }
1021*74a4d8c2SCharles.Forsyth }
1022*74a4d8c2SCharles.Forsyth }
1023*74a4d8c2SCharles.Forsyth free(buf);
1024*74a4d8c2SCharles.Forsyth poperror();
1025*74a4d8c2SCharles.Forsyth
1026*74a4d8c2SCharles.Forsyth if(dp->repl.p)
1027*74a4d8c2SCharles.Forsyth atareplinit(dp);
1028*74a4d8c2SCharles.Forsyth }
1029*74a4d8c2SCharles.Forsyth
1030*74a4d8c2SCharles.Forsyth enum
1031*74a4d8c2SCharles.Forsyth {
1032*74a4d8c2SCharles.Forsyth Maxloop= 10000,
1033*74a4d8c2SCharles.Forsyth };
1034*74a4d8c2SCharles.Forsyth
1035*74a4d8c2SCharles.Forsyth /*
1036*74a4d8c2SCharles.Forsyth * we get an interrupt for every sector transferred
1037*74a4d8c2SCharles.Forsyth */
1038*74a4d8c2SCharles.Forsyth static void
ataintr(Ureg *,void * arg)1039*74a4d8c2SCharles.Forsyth ataintr(Ureg*, void *arg)
1040*74a4d8c2SCharles.Forsyth {
1041*74a4d8c2SCharles.Forsyth Controller *cp;
1042*74a4d8c2SCharles.Forsyth Drive *dp;
1043*74a4d8c2SCharles.Forsyth long loop;
1044*74a4d8c2SCharles.Forsyth char *addr;
1045*74a4d8c2SCharles.Forsyth
1046*74a4d8c2SCharles.Forsyth cp = arg;
1047*74a4d8c2SCharles.Forsyth dp = cp->dp;
1048*74a4d8c2SCharles.Forsyth
1049*74a4d8c2SCharles.Forsyth ilock(&cp->reglock);
1050*74a4d8c2SCharles.Forsyth
1051*74a4d8c2SCharles.Forsyth loop = 0;
1052*74a4d8c2SCharles.Forsyth while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){
1053*74a4d8c2SCharles.Forsyth if(++loop > Maxloop) {
1054*74a4d8c2SCharles.Forsyth DPRINT("cmd=%lux status=%lux\n",
1055*74a4d8c2SCharles.Forsyth cp->cmd, inb(cp->pbase+Pstatus));
1056*74a4d8c2SCharles.Forsyth panic("ataintr: wait busy");
1057*74a4d8c2SCharles.Forsyth }
1058*74a4d8c2SCharles.Forsyth }
1059*74a4d8c2SCharles.Forsyth
1060*74a4d8c2SCharles.Forsyth switch(cp->cmd){
1061*74a4d8c2SCharles.Forsyth case Cwrite:
1062*74a4d8c2SCharles.Forsyth if(cp->status & Serr){
1063*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
1064*74a4d8c2SCharles.Forsyth cp->cmd = 0;
1065*74a4d8c2SCharles.Forsyth cp->error = inb(cp->pbase+Perror);
1066*74a4d8c2SCharles.Forsyth wakeup(&cp->r);
1067*74a4d8c2SCharles.Forsyth break;
1068*74a4d8c2SCharles.Forsyth }
1069*74a4d8c2SCharles.Forsyth cp->sofar++;
1070*74a4d8c2SCharles.Forsyth if(cp->sofar < cp->nsecs){
1071*74a4d8c2SCharles.Forsyth loop = 0;
1072*74a4d8c2SCharles.Forsyth while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0)
1073*74a4d8c2SCharles.Forsyth if(++loop > Maxloop) {
1074*74a4d8c2SCharles.Forsyth DPRINT("cmd=%lux status=%lux\n",
1075*74a4d8c2SCharles.Forsyth cp->cmd, inb(cp->pbase+Pstatus));
1076*74a4d8c2SCharles.Forsyth panic("ataintr: write");
1077*74a4d8c2SCharles.Forsyth }
1078*74a4d8c2SCharles.Forsyth addr = cp->buf;
1079*74a4d8c2SCharles.Forsyth if(addr){
1080*74a4d8c2SCharles.Forsyth addr += cp->sofar*dp->bytes;
1081*74a4d8c2SCharles.Forsyth outss(cp->pbase+Pdata, addr, dp->bytes/2);
1082*74a4d8c2SCharles.Forsyth }
1083*74a4d8c2SCharles.Forsyth } else{
1084*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
1085*74a4d8c2SCharles.Forsyth cp->cmd = 0;
1086*74a4d8c2SCharles.Forsyth wakeup(&cp->r);
1087*74a4d8c2SCharles.Forsyth }
1088*74a4d8c2SCharles.Forsyth break;
1089*74a4d8c2SCharles.Forsyth case Cread:
1090*74a4d8c2SCharles.Forsyth case Cident:
1091*74a4d8c2SCharles.Forsyth loop = 0;
1092*74a4d8c2SCharles.Forsyth while((cp->status & (Serr|Sdrq)) == 0){
1093*74a4d8c2SCharles.Forsyth if(++loop > Maxloop) {
1094*74a4d8c2SCharles.Forsyth DPRINT("cmd=%lux status=%lux\n",
1095*74a4d8c2SCharles.Forsyth cp->cmd, inb(cp->pbase+Pstatus));
1096*74a4d8c2SCharles.Forsyth panic("ataintr: read/ident");
1097*74a4d8c2SCharles.Forsyth }
1098*74a4d8c2SCharles.Forsyth cp->status = inb(cp->pbase+Pstatus);
1099*74a4d8c2SCharles.Forsyth }
1100*74a4d8c2SCharles.Forsyth if(cp->status & Serr){
1101*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
1102*74a4d8c2SCharles.Forsyth cp->cmd = 0;
1103*74a4d8c2SCharles.Forsyth cp->error = inb(cp->pbase+Perror);
1104*74a4d8c2SCharles.Forsyth wakeup(&cp->r);
1105*74a4d8c2SCharles.Forsyth break;
1106*74a4d8c2SCharles.Forsyth }
1107*74a4d8c2SCharles.Forsyth addr = cp->buf;
1108*74a4d8c2SCharles.Forsyth if(addr){
1109*74a4d8c2SCharles.Forsyth addr += cp->sofar*dp->bytes;
1110*74a4d8c2SCharles.Forsyth inss(cp->pbase+Pdata, addr, dp->bytes/2);
1111*74a4d8c2SCharles.Forsyth }
1112*74a4d8c2SCharles.Forsyth cp->sofar++;
1113*74a4d8c2SCharles.Forsyth if(cp->sofar > cp->nsecs)
1114*74a4d8c2SCharles.Forsyth print("ataintr %d %d\n", cp->sofar, cp->nsecs);
1115*74a4d8c2SCharles.Forsyth if(cp->sofar >= cp->nsecs){
1116*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
1117*74a4d8c2SCharles.Forsyth if (cp->cmd == Cread)
1118*74a4d8c2SCharles.Forsyth cp->cmd = 0;
1119*74a4d8c2SCharles.Forsyth else
1120*74a4d8c2SCharles.Forsyth cp->cmd = Cident2;
1121*74a4d8c2SCharles.Forsyth wakeup(&cp->r);
1122*74a4d8c2SCharles.Forsyth }
1123*74a4d8c2SCharles.Forsyth break;
1124*74a4d8c2SCharles.Forsyth case Cinitparam:
1125*74a4d8c2SCharles.Forsyth case Csetbuf:
1126*74a4d8c2SCharles.Forsyth case Cidle:
1127*74a4d8c2SCharles.Forsyth case Cstandby:
1128*74a4d8c2SCharles.Forsyth case Cpowerdown:
1129*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
1130*74a4d8c2SCharles.Forsyth cp->cmd = 0;
1131*74a4d8c2SCharles.Forsyth wakeup(&cp->r);
1132*74a4d8c2SCharles.Forsyth break;
1133*74a4d8c2SCharles.Forsyth case Cident2:
1134*74a4d8c2SCharles.Forsyth cp->lastcmd = cp->cmd;
1135*74a4d8c2SCharles.Forsyth cp->cmd = 0;
1136*74a4d8c2SCharles.Forsyth break;
1137*74a4d8c2SCharles.Forsyth default:
1138*74a4d8c2SCharles.Forsyth print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n",
1139*74a4d8c2SCharles.Forsyth cp->cmd, cp->lastcmd, cp->status);
1140*74a4d8c2SCharles.Forsyth break;
1141*74a4d8c2SCharles.Forsyth }
1142*74a4d8c2SCharles.Forsyth
1143*74a4d8c2SCharles.Forsyth iunlock(&cp->reglock);
1144*74a4d8c2SCharles.Forsyth }
1145*74a4d8c2SCharles.Forsyth
1146*74a4d8c2SCharles.Forsyth void
hardclock(void)1147*74a4d8c2SCharles.Forsyth hardclock(void)
1148*74a4d8c2SCharles.Forsyth {
1149*74a4d8c2SCharles.Forsyth int drive;
1150*74a4d8c2SCharles.Forsyth Drive *dp;
1151*74a4d8c2SCharles.Forsyth Controller *cp;
1152*74a4d8c2SCharles.Forsyth int diff;
1153*74a4d8c2SCharles.Forsyth
1154*74a4d8c2SCharles.Forsyth if(spindowntime <= 0)
1155*74a4d8c2SCharles.Forsyth return;
1156*74a4d8c2SCharles.Forsyth
1157*74a4d8c2SCharles.Forsyth for(drive = 0; drive < nhard; drive++){
1158*74a4d8c2SCharles.Forsyth dp = &ata[drive];
1159*74a4d8c2SCharles.Forsyth cp = dp->cp;
1160*74a4d8c2SCharles.Forsyth
1161*74a4d8c2SCharles.Forsyth diff = TK2SEC(m->ticks - dp->usetime);
1162*74a4d8c2SCharles.Forsyth if((dp->state == Sspinning) && (diff >= spindowntime)){
1163*74a4d8c2SCharles.Forsyth ilock(&cp->reglock);
1164*74a4d8c2SCharles.Forsyth cp->cmd = Cstandby;
1165*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcount, 0);
1166*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0);
1167*74a4d8c2SCharles.Forsyth outb(cp->pbase+Pcmd, cp->cmd);
1168*74a4d8c2SCharles.Forsyth iunlock(&cp->reglock);
1169*74a4d8c2SCharles.Forsyth dp->state = Sstandby;
1170*74a4d8c2SCharles.Forsyth }
1171*74a4d8c2SCharles.Forsyth }
1172*74a4d8c2SCharles.Forsyth }
1173*74a4d8c2SCharles.Forsyth
1174*74a4d8c2SCharles.Forsyth Dev atadevtab = {
1175*74a4d8c2SCharles.Forsyth 'H',
1176*74a4d8c2SCharles.Forsyth "ata",
1177*74a4d8c2SCharles.Forsyth
1178*74a4d8c2SCharles.Forsyth devreset,
1179*74a4d8c2SCharles.Forsyth atainit,
1180*74a4d8c2SCharles.Forsyth ataattach,
1181*74a4d8c2SCharles.Forsyth devdetach,
1182*74a4d8c2SCharles.Forsyth devclone,
1183*74a4d8c2SCharles.Forsyth atawalk,
1184*74a4d8c2SCharles.Forsyth atastat,
1185*74a4d8c2SCharles.Forsyth ataopen,
1186*74a4d8c2SCharles.Forsyth devcreate,
1187*74a4d8c2SCharles.Forsyth ataclose,
1188*74a4d8c2SCharles.Forsyth ataread,
1189*74a4d8c2SCharles.Forsyth devbread,
1190*74a4d8c2SCharles.Forsyth atawrite,
1191*74a4d8c2SCharles.Forsyth devbwrite,
1192*74a4d8c2SCharles.Forsyth devremove,
1193*74a4d8c2SCharles.Forsyth devwstat,
1194*74a4d8c2SCharles.Forsyth };
1195