Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /* |
2 | * Project: S.Ha.R.K. |
||
3 | * |
||
4 | * Coordinators: |
||
5 | * Giorgio Buttazzo <giorgio@sssup.it> |
||
6 | * Paolo Gai <pj@gandalf.sssup.it> |
||
7 | * |
||
8 | * Authors : |
||
9 | * Paolo Gai <pj@gandalf.sssup.it> |
||
10 | * Massimiliano Giorgi <massy@gandalf.sssup.it> |
||
11 | * Luca Abeni <luca@gandalf.sssup.it> |
||
12 | * (see the web pages for full authors list) |
||
13 | * |
||
14 | * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy) |
||
15 | * |
||
16 | * http://www.sssup.it |
||
17 | * http://retis.sssup.it |
||
18 | * http://shark.sssup.it |
||
19 | */ |
||
20 | |||
21 | |||
22 | /*************************************** |
||
23 | |||
24 | CVS : $Id: idelow.c,v 1.1.1.1 2002-03-29 14:12:49 pj Exp $ |
||
25 | |||
26 | Revision: $Revision: 1.1.1.1 $ |
||
27 | |||
28 | Last update: $Date: 2002-03-29 14:12:49 $ |
||
29 | |||
30 | This module is responsable of the protocol between the IDE device driver |
||
31 | interface and the host (the computer). |
||
32 | |||
33 | ***************************************/ |
||
34 | |||
35 | /* |
||
36 | * Copyright (C) 1999,2000 Massimiliano Giorgi |
||
37 | * |
||
38 | * This program is free software; you can redistribute it and/or modify |
||
39 | * it under the terms of the GNU General Public License as published by |
||
40 | * the Free Software Foundation; either version 2 of the License, or |
||
41 | * (at your option) any later version. |
||
42 | * |
||
43 | * This program is distributed in the hope that it will be useful, |
||
44 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
45 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
46 | * GNU General Public License for more details. |
||
47 | * |
||
48 | * You should have received a copy of the GNU General Public License |
||
49 | * along with this program; if not, write to the Free Software |
||
50 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
51 | * |
||
52 | */ |
||
53 | |||
54 | #include "glue.h" |
||
55 | #include <fs/bdevinit.h> |
||
56 | #include <fs/magic.h> |
||
57 | #include <fs/assert.h> |
||
58 | #include <fs/util.h> |
||
59 | #include <fs/maccess.h> |
||
60 | |||
61 | #include "bdev.h" |
||
62 | #include "phdsk.h" |
||
63 | #include "lodsk.h" |
||
64 | #include "ide.h" |
||
65 | #include "idereq.h" |
||
66 | #include "bqueue.h" |
||
67 | |||
68 | /*+ some kernel depend features implemented +*/ |
||
69 | #include "ideglue.h" |
||
70 | |||
71 | /* |
||
72 | * TRACER FLAGS |
||
73 | */ |
||
74 | |||
75 | /* if defined use tracer user events 1 and 2 before and after blocking |
||
76 | * for synchronization (so we can compute the waiting time for a |
||
77 | * request) |
||
78 | */ |
||
79 | #define TRACEWAIT |
||
80 | #undef TRACEWAIT |
||
81 | |||
82 | #ifdef TRACEWAIT |
||
83 | #include <trace/types.h> |
||
84 | #include <kernel/trace.h> |
||
85 | #endif |
||
86 | |||
87 | /* |
||
88 | * FLAGS |
||
89 | */ |
||
90 | |||
91 | /* if defined: |
||
92 | * enable "set features" commands (so we can set features on ide drives). |
||
93 | */ |
||
94 | #define IDE_ENABLESETFEATURES 1 |
||
95 | //#undef IDE_ENABLESETFEATURES |
||
96 | |||
97 | /* if defined: |
||
98 | * add a delay into the IRQ handler |
||
99 | * (my old cdrom seems to clear the IRQ at the end of the data in/out |
||
100 | * not when reading the STATUS register) |
||
101 | * PS: if the DEBUG_SERVER is defined this delay isn't required. |
||
102 | */ |
||
103 | #define IDE_OLDATAPIDELAY 1 |
||
104 | #undef IDE_OLDATAPIDELAY |
||
105 | |||
106 | /* if defined: |
||
107 | * after the soft reset timeout expired do a soft reset |
||
108 | * also if the device is busy |
||
109 | * (some old cdrom seems not to clear the busy bits ?!?) |
||
110 | */ |
||
111 | #define IDE_FORCERESET 1 |
||
112 | //#undef IDE_FORCERESET |
||
113 | |||
114 | /* |
||
115 | * if defined: |
||
116 | * after issuing a command does not test for command in progress |
||
117 | * (does not read the status register!) |
||
118 | * DANGER: need for all TX motherboard |
||
119 | */ |
||
120 | #define IDE_SKIPSTATUSTEST 1 |
||
121 | //#undef IDE_SKIPSTATUSTEST |
||
122 | |||
123 | /* |
||
124 | * if defined: |
||
125 | * skip all test when issuing a command! |
||
126 | * (it imply IDE_SKIPSTATUSTEST) |
||
127 | * DANGER: need on some TX motherboard |
||
128 | * on few TX motherboards PIO mode is not safe (DMA must be used) |
||
129 | */ |
||
130 | #define IDE_SKIPALLTEST 1 |
||
131 | #undef IDE_SKIPALLTEST |
||
132 | |||
133 | #ifdef IDE_SKIPALLTEST |
||
134 | #define IDE_SKIPSTATUSTEST 1 |
||
135 | #endif |
||
136 | |||
137 | /* |
||
138 | * DEBUG |
||
139 | */ |
||
140 | |||
141 | /* show server activity */ |
||
142 | #define DEBUG_SERVER KERN_DEBUG |
||
143 | #undef DEBUG_SERVER |
||
144 | |||
145 | /* show request and result */ |
||
146 | #define DEBUG_SHOWREQUEST KERN_DEBUG |
||
147 | #undef DEBUG_SHOWREQUEST |
||
148 | |||
149 | /* trace soft reset function */ |
||
150 | #define DEBUG_SOFTRESET KERN_DEBUG |
||
151 | #undef DEBUG_SOFTRESET |
||
152 | |||
153 | /* trace REQ_EPILOG (the epilog of every device request) */ |
||
154 | #define DEBUG_REQEPILOG KERN_DEBUG |
||
155 | #undef DEBUG_REQEPILOG |
||
156 | |||
157 | /* trace do_io_request() (WARNIG can cause a deadline miss)*/ |
||
158 | #define DEBUG_IOREQUEST KERN_DEBUG |
||
159 | #undef DEBUG_IOREQUEST |
||
160 | |||
161 | /**/ |
||
162 | |||
163 | #ifdef DEBUG_SERVER |
||
164 | #define printk0(ideif,fmt,args...) \ |
||
165 | printk(DEBUG_SERVER "ide%i server:" fmt,ideif,##args) |
||
166 | #else |
||
167 | #define printk0(fmt,args...) |
||
168 | #endif |
||
169 | |||
170 | #ifdef DEBUG_SHOWREQUEST |
||
171 | #define printk1(ideif,fmt,args...) \ |
||
172 | printk(DEBUG_SHOWREQUEST "ide%i request:" fmt,ideif,##args) |
||
173 | #else |
||
174 | #define printk1(fmt,args...) |
||
175 | #endif |
||
176 | |||
177 | #ifdef DEBUG_SOFTRESET |
||
178 | #define printk2(ideif,fmt,args...) \ |
||
179 | printk(DEBUG_SOFTRESET "ide%i soft reset:" fmt,ideif,##args) |
||
180 | #else |
||
181 | #define printk2(fmt,args...) |
||
182 | #endif |
||
183 | |||
184 | #ifdef DEBUG_REQEPILOG |
||
185 | #define printk3(ideif,fmt,args...) \ |
||
186 | printk(DEBUG_REQEPILOG "ide%i req_epilog:" fmt,ideif,##args) |
||
187 | #else |
||
188 | #define printk3(fmt,args...) |
||
189 | #endif |
||
190 | |||
191 | #ifdef DEBUG_IOREQUEST |
||
192 | #define printk4(ideif,fmt,args...) \ |
||
193 | printk(DEBUG_IOREQUEST fmt) |
||
194 | #else |
||
195 | #define printk4(fmt,args...) |
||
196 | #endif |
||
197 | |||
198 | /* |
||
199 | * |
||
200 | * REGISTERS |
||
201 | * |
||
202 | */ |
||
203 | |||
204 | /* |
||
205 | * from ATA/ATAPI 4 (T13/1153D revision 18) |
||
206 | * paragraph 7.x |
||
207 | */ |
||
208 | |||
209 | /* io_port registers (usually on 0x1f0 for first IDE interface) */ |
||
210 | #define REG_DATA 0x00 |
||
211 | #define REG_ERROR 0x01 |
||
212 | #define REG_FEATURES 0x01 |
||
213 | #define REG_SECCOU 0x02 |
||
214 | #define REG_SECNUM 0x03 |
||
215 | #define REG_CYLLOW 0x04 |
||
216 | #define REG_CYLHIG 0x05 |
||
217 | #define REG_DEVHEAD 0x06 |
||
218 | #define REG_STATUS 0x07 |
||
219 | #define REG_COMMAND 0x07 |
||
220 | |||
221 | /* to register the i/o space */ |
||
222 | #define IOPORT_OFFSET 0 |
||
223 | #define IOPORT_LEN 8 |
||
224 | |||
225 | /* io_port2 registers (usually on 0x3f0 for first IDE interface) */ |
||
226 | #define REG_ALTSTATUS 0x06 |
||
227 | #define REG_DEVCTRL 0x06 |
||
228 | |||
229 | /* to register the i/o space */ |
||
230 | #define IOPORT2_OFFSET 6 |
||
231 | #define IOPORT2_LEN 1 |
||
232 | |||
233 | /* to use with VM_in/VM_out */ |
||
234 | /* for read/write */ |
||
235 | #define IDE_REG_DATA (ide[ideif].io_port+REG_DATA) |
||
236 | #define IDE_REG_SECCOU (ide[ideif].io_port+REG_SECCOU) |
||
237 | #define IDE_REG_SECNUM (ide[ideif].io_port+REG_SECNUM) |
||
238 | #define IDE_REG_CYLLOW (ide[ideif].io_port+REG_CYLLOW) |
||
239 | #define IDE_REG_CYLHIG (ide[ideif].io_port+REG_CYLHIG) |
||
240 | #define IDE_REG_DEVHEAD (ide[ideif].io_port+REG_DEVHEAD) |
||
241 | /* for read */ |
||
242 | #define IDE_REG_STATUS (ide[ideif].io_port+REG_STATUS) |
||
243 | #define IDE_REG_ERROR (ide[ideif].io_port+REG_ERROR) |
||
244 | #define IDE_REG_ALTSTATUS (ide[ideif].io_port2+REG_ALTSTATUS) |
||
245 | /* for write */ |
||
246 | #define IDE_REG_COMMAND (ide[ideif].io_port+REG_COMMAND) |
||
247 | #define IDE_REG_FEATURES (ide[ideif].io_port+REG_ERROR) |
||
248 | #define IDE_REG_DEVCTRL (ide[ideif].io_port2+REG_DEVCTRL) |
||
249 | |||
250 | /* for status & alt_status register */ |
||
251 | #define STATUS_BUSY 0x80 |
||
252 | #define STATUS_DRDY 0x40 |
||
253 | #define STATUS_R_FAULT 0x20 |
||
254 | #define STATUS_R_SEEKCOM 0x10 |
||
255 | #define STATUS_DRQ 0x08 |
||
256 | #define STATUS_R_DWC 0x04 |
||
257 | #define STATUS_R_CMDPROG 0x02 |
||
258 | #define STATUS_ERR 0x01 |
||
259 | |||
260 | /* for error register */ |
||
261 | #define ERROR_OBS_BADBLOCK 0x80 |
||
262 | #define ERROR_OBS_CRCECC 0x40 |
||
263 | #define ERROR_OBS_IDNOTFOUND 0x10 |
||
264 | #define ERROR_ABORTCMD 0x04 |
||
265 | #define ERROR_OBS_TRACK00 0x02 |
||
266 | #define ERROR_OBS_DAMNOTFOUND 0x01 |
||
267 | |||
268 | /* for devhead register */ |
||
269 | #define DEVHEAD_DEV 0x10 |
||
270 | |||
271 | /* for devctrl (device control) register */ |
||
272 | #define DEVCTRL_SRST 0x04 |
||
273 | #define DEVCTRL_NIEN 0x02 |
||
274 | |||
275 | #define DEVCTRL_SOFTRESET (DEVCTRL_SRST) |
||
276 | #define DEVCTRL_ENABLEINT (0) |
||
277 | #define DEVCTRL_DISABLEINT (DEVCTRL_NIEN) |
||
278 | |||
279 | #define DEVCTRL_NORMALOP (DEVCTRL_ENABLEINT) |
||
280 | |||
281 | /* |
||
282 | * these are not from ATA specification |
||
283 | */ |
||
284 | |||
285 | /* bus master registers */ |
||
286 | #define REG_BMICX 0 |
||
287 | #define REG_BMISX 2 |
||
288 | #define REG_BMIDTPX 4 |
||
289 | |||
290 | /* to use with VM_in/VM_out */ |
||
291 | #define BM_REG_COMMAND (ide[ideif].io_bmdma+REG_BMICX) |
||
292 | #define BM_REG_STATUS (ide[ideif].io_bmdma+REG_BMISX) |
||
293 | #define BM_REG_PRDADDR (ide[ideif].io_bmdma+REG_BMIDTPX) |
||
294 | |||
295 | /* to register the i/o space */ |
||
296 | #define BMDMAPORT_OFFSET 0 |
||
297 | #define BMDMAPORT_LEN 8 |
||
298 | |||
299 | /* |
||
300 | * |
||
301 | * |
||
302 | * |
||
303 | */ |
||
304 | |||
305 | static int decode_error_result(int ideif) |
||
306 | { |
||
307 | |||
308 | BYTE error; |
||
309 | error=inp(IDE_REG_ERROR); |
||
310 | |||
311 | /* |
||
312 | * obsoleted by ATA 4 |
||
313 | * |
||
314 | if (error&ERR_BADBLOCK) return IDE_ERR_BADBLOCK; |
||
315 | else if (error&ERR_CRCECC) return IDE_ERR_CRCECC; |
||
316 | else if (error&ERR_IDNOTFOUND) return IDE_ERR_IDNOTFOUND; |
||
317 | else if (error&ERR_ABORTCMD) return IDE_ERR_ABORTCMD; |
||
318 | else if (error&ERR_TRACK00) return IDE_ERR_TRACK00; |
||
319 | else if (error&ERR_DAMNOTFOUND) return IDE_ERR_DAMNOTFOUND; |
||
320 | */ |
||
321 | |||
322 | if (error&ERROR_ABORTCMD) return IDE_ERR_ABORTCMD; |
||
323 | return IDE_ERR_UNKNOWN; |
||
324 | } |
||
325 | |||
326 | static void debug_status(char *s,BYTE status,BYTE mask) |
||
327 | { |
||
328 | printk(IDEDEBUGLOG "%s: %s\n",s,status&mask?"yes":"no"); |
||
329 | } |
||
330 | |||
331 | void ide_dump_interface_status(int ideif) |
||
332 | { |
||
333 | BYTE status; |
||
334 | |||
335 | printk(IDEDEBUGLOG "ide%i status\n",ideif); |
||
336 | |||
337 | status=inp(IDE_REG_ALTSTATUS); |
||
338 | |||
339 | debug_status("busy ",status,STATUS_BUSY); |
||
340 | if (status&STATUS_BUSY) return; |
||
341 | |||
342 | debug_status("ready ",status,STATUS_DRDY); |
||
343 | //debug_status("write fault ",status,ST_WRFAULT); |
||
344 | //debug_status("seek complete ",status,ST_SEEKCOM); |
||
345 | debug_status("data request ",status,STATUS_DRQ); |
||
346 | //debug_status("data was corrected ",status,ST_DWC); |
||
347 | //debug_status("command in progress",status,ST_CMDPROG); |
||
348 | debug_status("error ",status,STATUS_ERR); |
||
349 | |||
350 | } |
||
351 | |||
352 | |||
353 | //#ifndef NDEBUG |
||
354 | |||
355 | /*+ for the IDE_ERR_??? constants +*/ |
||
356 | char *ide_error_msg[]={ |
||
357 | "no error", |
||
358 | "there are too much request pending", |
||
359 | "there was an interrupt but the interface is busy or can not do a command", |
||
360 | "IDE error: bad block", |
||
361 | "IDE error: crc/ecc error", |
||
362 | "IDE error: sector id not found", |
||
363 | "IDE error: abort command", |
||
364 | "IDE error: track00 seek error", |
||
365 | "IDE error: DAM not found", |
||
366 | "generic error", |
||
367 | "there was an interrupt, we aspect data but there is not data", |
||
368 | "there was an interrupt, we do not aspect data but there is data", |
||
369 | "interface not ready for a command", |
||
370 | "a timeout waiting for a reply", |
||
371 | "the interface must be busy but it is not", |
||
372 | "device fault" |
||
373 | }; |
||
374 | |||
375 | //#endif |
||
376 | |||
377 | /* |
||
378 | * |
||
379 | * |
||
380 | * |
||
381 | */ |
||
382 | |||
383 | /* on i386 machine */ |
||
384 | /* (todo better) */ |
||
385 | /* done better! */ |
||
386 | //#define ntohs(x) ((((x)&0xff00)>>8)|(((x)&0x00ff)<<8)) |
||
387 | |||
388 | /* Well... the strings reported are swapped so if we have |
||
389 | * a "Maxtor" hard disk the following string is reported: "aMtxro" |
||
390 | */ |
||
391 | |||
392 | /* from Linux kernel (modified!) */ |
||
393 | static void ide_fixstring (BYTE *s, const int bytecount, const int byteswap) |
||
394 | { |
||
395 | BYTE *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */ |
||
396 | |||
397 | if (byteswap) { |
||
398 | /* convert from big-endian to host byte order */ |
||
399 | for (p = end ; p != s;) { |
||
400 | WORD *pp = (WORD *) (p -= 2); |
||
401 | *pp = ntohs(*pp); |
||
402 | } |
||
403 | } |
||
404 | |||
405 | /* strip leading blanks */ |
||
406 | while (s != end && *s == ' ') |
||
407 | ++s; |
||
408 | |||
409 | /* compress internal blanks and strip trailing blanks */ |
||
410 | while (s != end && *s) { |
||
411 | if (*s++ != ' ' || (s != end && *s && *s != ' ')) |
||
412 | *p++ = *(s-1); |
||
413 | } |
||
414 | |||
415 | /* wipe out trailing garbage */ |
||
416 | while (p != end) |
||
417 | *p++ = '\0'; |
||
418 | } |
||
419 | |||
420 | static void ide_fixdiskid(struct ata_diskid *ptr) |
||
421 | { |
||
422 | ide_fixstring(ptr->firmware,sizeof(ptr->firmware),1); |
||
423 | ptr->firmware[sizeof(ptr->firmware)-1]='\0'; |
||
424 | ide_fixstring(ptr->model,sizeof(ptr->model),1); |
||
425 | ptr->model[sizeof(ptr->model)-1]='\0'; |
||
426 | ide_fixstring(ptr->serial,sizeof(ptr->serial),1); |
||
427 | ptr->serial[sizeof(ptr->serial)-1]='\0'; |
||
428 | } |
||
429 | |||
430 | static void ide_fixatapidiskid(struct atapi_diskid *ptr) |
||
431 | { |
||
432 | ide_fixstring(ptr->firmware,sizeof(ptr->firmware),1); |
||
433 | ptr->firmware[sizeof(ptr->firmware)-1]='\0'; |
||
434 | ide_fixstring(ptr->model,sizeof(ptr->model),1); |
||
435 | ptr->model[sizeof(ptr->model)-1]='\0'; |
||
436 | ide_fixstring(ptr->serial,sizeof(ptr->serial),1); |
||
437 | ptr->serial[sizeof(ptr->serial)-1]='\0'; |
||
438 | } |
||
439 | |||
440 | static void lba2chs(int ideif, int id, DWORD lsector, int req) |
||
441 | { |
||
442 | |||
443 | if (ide[ideif].info[id].use_lba) { |
||
444 | idereq[req].secnum=lsector&0xff; |
||
445 | lsector>>=8; |
||
446 | idereq[req].cyllow=lsector&0xff; |
||
447 | lsector>>=8; |
||
448 | idereq[req].cylhig=lsector&0xff; |
||
449 | lsector>>=8; |
||
450 | idereq[req].devhead=0xe0|(lsector&0x0f)|((id&0x01)<<4); |
||
451 | } else { |
||
452 | /* for old hard-disk; is this correct? */ |
||
453 | int sect,head,cyl,track; |
||
454 | struct dskgeometry *drive=&(ide[ideif].pdisk[id]->pd_phgeom); |
||
455 | track = lsector / drive->sectors; |
||
456 | sect = lsector % drive->sectors + 1; |
||
457 | idereq[req].secnum=sect; |
||
458 | head = track % drive->heads; |
||
459 | cyl = track / drive->heads; |
||
460 | idereq[req].cyllow=cyl&0xff; |
||
461 | idereq[req].cylhig=(cyl>>8)&0xff; |
||
462 | idereq[req].devhead=0xa0|(head&0x0f)|((id&0x01)<<4); |
||
463 | } |
||
464 | } |
||
465 | |||
466 | int ide_register(__uint16_t io_port, __uint16_t io_port2, |
||
467 | __uint8_t irq, |
||
468 | __uint8_t dma, __uint16_t io_bmdma) |
||
469 | { |
||
470 | //struct phdskinfo disk; |
||
471 | //MODEL m=BASE_MODEL; |
||
472 | //int ind; |
||
473 | int ideif; |
||
474 | int res; |
||
475 | |||
476 | //int req; |
||
477 | //int ret; |
||
478 | |||
479 | /* find an IDE interface sequential number */ |
||
480 | ideif=nextideif(); |
||
481 | if (ideif==MAXIDEINTERFACES) { |
||
482 | if (ide_showinfo_flag) |
||
483 | printk(IDELOG "ide: can't register (unavailable space)"); |
||
484 | return -1; |
||
485 | } |
||
486 | |||
487 | /* request to use resources... */ |
||
488 | if (!__request_irq(irq)) return -1; |
||
489 | if (!__request_io_space(io_port+IOPORT_OFFSET,IOPORT_LEN)) { |
||
490 | mark_ide_free(ideif); |
||
491 | __release_irq(irq); |
||
492 | return -1; |
||
493 | } |
||
494 | if (!__request_io_space(io_port2+IOPORT2_OFFSET,IOPORT2_LEN)) { |
||
495 | mark_ide_free(ideif); |
||
496 | __release_irq(irq); |
||
497 | __release_io_space(io_port+IOPORT_OFFSET,IOPORT_LEN); |
||
498 | return -1; |
||
499 | } |
||
500 | if (io_bmdma!=0) |
||
501 | if (!__request_io_space(io_bmdma+BMDMAPORT_OFFSET,BMDMAPORT_LEN)) { |
||
502 | mark_ide_free(ideif); |
||
503 | __release_irq(irq); |
||
504 | __release_io_space(io_port+IOPORT_OFFSET,IOPORT_LEN); |
||
505 | __release_io_space(io_port2+IOPORT2_OFFSET,IOPORT2_LEN); |
||
506 | return -1; |
||
507 | } |
||
508 | |||
509 | #ifdef _PARANOIA |
||
510 | ide[ideif].magic=IDE_MAGIC; |
||
511 | #endif |
||
512 | |||
513 | ide[ideif].io_port=io_port; |
||
514 | ide[ideif].io_port2=io_port2; |
||
515 | ide[ideif].irq=irq; |
||
516 | ide[ideif].dma=dma; |
||
517 | ide[ideif].io_bmdma=io_bmdma; |
||
518 | ide[ideif].pdisk[IDE_MASTER]=NULL; |
||
519 | ide[ideif].info[IDE_MASTER].use_lba=0; |
||
520 | ide[ideif].pdisk[IDE_SLAVE]=NULL; |
||
521 | ide[ideif].info[IDE_SLAVE].use_lba=0; |
||
522 | ide[ideif].actreq=-1; |
||
523 | ide[ideif].actdrv=-1; |
||
524 | bqueue_init(&ide[ideif].queue[0]); |
||
525 | bqueue_init(&ide[ideif].queue[1]); |
||
526 | |||
527 | /* |
||
528 | * glue initialization |
||
529 | */ |
||
530 | |||
531 | res=ide_glue_activate_interface(ideif); |
||
532 | if (res==-1) { |
||
533 | mark_ide_free(ideif); |
||
534 | __release_irq(irq); |
||
535 | __release_io_space(io_port+IOPORT_OFFSET,IOPORT_LEN); |
||
536 | __release_io_space(io_port2+IOPORT2_OFFSET,IOPORT2_LEN); |
||
537 | if (io_bmdma!=0) |
||
538 | __release_io_space(io_bmdma+BMDMAPORT_OFFSET,BMDMAPORT_LEN); |
||
539 | return -1; |
||
540 | } |
||
541 | |||
542 | return ideif; |
||
543 | } |
||
544 | |||
545 | void ide_unregister(int ideif) |
||
546 | { |
||
547 | |||
548 | ide_glue_unactivate_interface(ideif); |
||
549 | |||
550 | __release_irq(ide[ideif].irq); |
||
551 | __release_io_space(ide[ideif].io_port+IOPORT_OFFSET,IOPORT_LEN); |
||
552 | __release_io_space(ide[ideif].io_port2+IOPORT2_OFFSET,IOPORT2_LEN); |
||
553 | |||
554 | mark_ide_free(ideif); |
||
555 | //if (ideif!=ideiftail-1) |
||
556 | // memcpy(ide+ideif,ide+ideiftail-1,sizeof(ideinfo_t)); |
||
557 | } |
||
558 | |||
559 | /* |
||
560 | * |
||
561 | * |
||
562 | * |
||
563 | */ |
||
564 | |||
565 | /* commands used */ |
||
566 | #define ATA_READ 0x20 |
||
567 | #define ATA_WRITE 0x30 |
||
568 | #define ATA_SEEK 0x70 |
||
569 | #define ATA_DMAREAD 0xc8 |
||
570 | #define ATA_DMAWRITE 0xca |
||
571 | #define ATA_IDENTIFY 0xec |
||
572 | #define ATA_PIDENTIFY 0xa1 |
||
573 | #define ATA_SETFEATURE 0xef |
||
574 | |||
575 | /* for 'set feature' command */ |
||
576 | #define ATA_FEATURE_ENABLELOOKAHEAD 0xaa |
||
577 | #define ATA_FEATURE_DISABLELOOKAHEAD 0x55 |
||
578 | #define ATA_FEATURE_SETTRANSFERTMODE 0x03 |
||
579 | |||
580 | /* commands type */ |
||
581 | #define ATA_TYPE_PIOIN 0 |
||
582 | #define ATA_TYPE_PIOOUT 1 |
||
583 | #define ATA_TYPE_DMA 2 |
||
584 | #define ATA_TYPE_NODATA 3 |
||
585 | |||
586 | static inline int cmd2type(int cmd) |
||
587 | { |
||
588 | switch(cmd) { |
||
589 | case ATA_READ: |
||
590 | case ATA_IDENTIFY: |
||
591 | case ATA_PIDENTIFY: |
||
592 | return ATA_TYPE_PIOIN; |
||
593 | case ATA_WRITE: |
||
594 | return ATA_TYPE_PIOOUT; |
||
595 | case ATA_DMAREAD: |
||
596 | case ATA_DMAWRITE: |
||
597 | return ATA_TYPE_DMA; |
||
598 | case ATA_SEEK: |
||
599 | case ATA_SETFEATURE: |
||
600 | return ATA_TYPE_NODATA; |
||
601 | } |
||
602 | return ATA_TYPE_NODATA; |
||
603 | } |
||
604 | |||
605 | #if defined(DEBUG_SERVER)||defined(DEBUG_SHOWREQUEST) |
||
606 | static char *cmd2str(int cmd) |
||
607 | { |
||
608 | switch(cmd) { |
||
609 | case ATA_READ: return "'read'"; |
||
610 | case ATA_WRITE: return "'write'"; |
||
611 | case ATA_SEEK: return "'seek'"; |
||
612 | case ATA_DMAREAD: return "'dma read'"; |
||
613 | case ATA_DMAWRITE: return "'dma write'"; |
||
614 | case ATA_IDENTIFY: return "'identify'"; |
||
615 | case ATA_PIDENTIFY: return "'packet identify'"; |
||
616 | case ATA_SETFEATURE: return "'set feature'"; |
||
617 | } |
||
618 | return "'unknown'"; |
||
619 | } |
||
620 | #endif |
||
621 | |||
622 | /* |
||
623 | * from ATA/ATAPI 4 (T13/1153D revision 18) |
||
624 | * paragraph 9.7 (figure 12) |
||
625 | */ |
||
626 | |||
627 | #define RETRY 3 |
||
628 | |||
629 | |||
630 | /*from Linux 2.2.13*/ |
||
631 | /* |
||
632 | static int do_io_request(int ideif) |
||
633 | { |
||
634 | int req=ide[ideif].reqhead; |
||
635 | |||
636 | VM_out(IDE_REG_DEVCTRL,DEVCTRL_NORMALOP); |
||
637 | outp(IDE_REG_SECCOU,idereq[req].seccou); |
||
638 | |||
639 | outp(IDE_REG_SECNUM,idereq[req].secnum); |
||
640 | outp(IDE_REG_CYLLOW,idereq[req].cyllow); |
||
641 | outp(IDE_REG_CYLHIG,idereq[req].cylhig); |
||
642 | outp(IDE_REG_DEVHEAD,idereq[req].devhead); |
||
643 | |||
644 | outp(IDE_REG_COMMAND,idereq[req].cmd); |
||
645 | |||
646 | return IDE_OK; |
||
647 | } |
||
648 | */ |
||
649 | |||
650 | static int do_io_request(int ideif) |
||
651 | { |
||
652 | int req; |
||
653 | BYTE status; |
||
654 | int n; |
||
655 | WORD *ptr; |
||
656 | #ifndef IDE_SKIPALLTEST |
||
657 | int retries; |
||
658 | #endif |
||
659 | |||
660 | printk4(ideif,"A"); |
||
661 | |||
662 | //outp(IDE_REG_DEVCTRL,DEVCTRL_NORMALOP); |
||
663 | //outp(IDE_REG_SECCOU,idereq[req].seccou); |
||
664 | |||
665 | req=first_idereq(ideif); |
||
666 | assertk(req!=NIL); |
||
667 | |||
668 | /* requirement for some commands */ |
||
669 | switch(idereq[req].cmd) { |
||
670 | |||
671 | /* DRDY must be one */ |
||
672 | case ATA_READ: |
||
673 | case ATA_DMAREAD: |
||
674 | case ATA_WRITE: |
||
675 | case ATA_DMAWRITE: |
||
676 | case ATA_SEEK: |
||
677 | case ATA_IDENTIFY: |
||
678 | case ATA_SETFEATURE: |
||
679 | |||
680 | #ifndef IDE_SKIPALLTEST |
||
681 | retries=RETRY; |
||
682 | while (--retries>=0) { |
||
683 | status=inp(IDE_REG_STATUS); |
||
684 | if ((status&STATUS_DRDY)!=0) break; |
||
685 | } |
||
686 | if (retries<0) return idereq[req].result=IDE_ERR_NOTDRDY; |
||
687 | break; |
||
688 | #endif |
||
689 | |||
690 | /* no requirement */ |
||
691 | case ATA_PIDENTIFY: |
||
692 | break; |
||
693 | } |
||
694 | |||
695 | printk4(ideif,"B"); |
||
696 | |||
697 | /* a command can be issued when BUSY==0 && DRQ==0 */ |
||
698 | #ifndef IDE_SKIPALLTEST |
||
699 | retries=RETRY; |
||
700 | while (--retries>=0) { |
||
701 | status=inp(IDE_REG_STATUS); |
||
702 | if ((status&STATUS_BUSY)==0&&(status&STATUS_DRQ)==0) break; |
||
703 | } |
||
704 | if (retries<0) { |
||
705 | /* if the ide device is in stand-by the request fail! */ |
||
706 | if (status&STATUS_BUSY) return idereq[req].result=IDE_ERR_BUSY; |
||
707 | else return idereq[req].result=IDE_ERR_NOTREADY; |
||
708 | } |
||
709 | #endif |
||
710 | |||
711 | printk4(ideif,"C"); |
||
712 | |||
713 | /* write "change device" register */ |
||
714 | outp(IDE_REG_DEVHEAD,idereq[req].devhead); |
||
715 | |||
716 | /* to wait for 400ns (I hope) */ |
||
717 | #ifndef IDE_SKIPALLTEST |
||
718 | inp(IDE_REG_ALTSTATUS); |
||
719 | #endif |
||
720 | |||
721 | /* wait for "change device" to take effect */ |
||
722 | #ifndef IDE_SKIPALLTEST |
||
723 | retries=RETRY; |
||
724 | while (--retries>=0) { |
||
725 | status=inp(IDE_REG_STATUS); |
||
726 | if ((status&STATUS_BUSY)==0&&(status&STATUS_DRQ)==0) break; |
||
727 | } |
||
728 | if (retries<0) { |
||
729 | /* Well, if I do a command to a disk that does not exist an |
||
730 | * interrupt is generated... so I MUST report no error |
||
731 | * (the error is manage into the ide server) |
||
732 | */ |
||
733 | return IDE_OK; |
||
734 | if (status&STATUS_BUSY) return idereq[req].result=IDE_ERR_BUSY; |
||
735 | else return idereq[req].result=IDE_ERR_NOTREADY; |
||
736 | } |
||
737 | #endif |
||
738 | |||
739 | printk4(ideif,"D"); |
||
740 | |||
741 | /* write all the registers */ |
||
742 | outp(IDE_REG_FEATURES,idereq[req].features); |
||
743 | outp(IDE_REG_SECCOU,idereq[req].seccou); |
||
744 | outp(IDE_REG_SECNUM,idereq[req].secnum); |
||
745 | outp(IDE_REG_CYLLOW,idereq[req].cyllow); |
||
746 | outp(IDE_REG_CYLHIG,idereq[req].cylhig); |
||
747 | //outp(IDE_REG_DEVHEAD,idereq[req].devhead); |
||
748 | |||
749 | if (cmd2type(idereq[req].cmd)==ATA_TYPE_DMA) { |
||
750 | |||
751 | /* |
||
752 | * |
||
753 | * Bus Master DMA commands |
||
754 | * |
||
755 | */ |
||
756 | |||
757 | /* these code come from Linux 2.2.12 (modified!) */ |
||
758 | |||
759 | __uint32_t addr,*ptr; |
||
760 | unsigned int size; |
||
761 | int count; |
||
762 | |||
763 | /* make PRD table */ |
||
764 | |||
765 | addr=__lin_to_phy(idereq[req].buffer); |
||
766 | if (addr&3) { |
||
767 | /* misaligned buffer */ |
||
768 | printk(KERN_ERR "ide do_io_request: misaligned DMA buffer (0x%08lx)", |
||
769 | (long)addr); |
||
770 | return IDE_ERR_UNKNOWN; |
||
771 | } |
||
772 | size=IDE_SECTOR_SIZE; /* for now only 1 sector */ |
||
773 | |||
774 | ptr=ide[ideif].prd; |
||
775 | count=0; |
||
776 | while (size) { |
||
777 | if (++count>=MAXPRDENTRIES) { |
||
778 | /* table to small for the request */ |
||
779 | printk(KERN_ERR "ide do_io_request: PRD table too small"); |
||
780 | return IDE_ERR_UNKNOWN; |
||
781 | } else { |
||
782 | unsigned int xcount, bcount = 0x10000 - (addr & 0xffff); |
||
783 | if (bcount > size) |
||
784 | bcount = size; |
||
785 | *ptr++ = addr; |
||
786 | xcount = bcount & 0xffff; |
||
787 | //if (is_trm290_chipset) |
||
788 | // xcount = ((xcount >> 2) - 1) << 16; |
||
789 | *ptr++ = xcount; |
||
790 | addr += bcount; |
||
791 | size -= bcount; |
||
792 | } |
||
793 | } |
||
794 | |||
795 | printk4(ideif,"E3"); |
||
796 | |||
797 | /* PRD table */ |
||
798 | outpd(BM_REG_PRDADDR,__lin_to_phy(ide[ideif].prd)); |
||
799 | |||
800 | /* specify r/w */ |
||
801 | if (idereq[req].cmd==ATA_DMAREAD) outp(BM_REG_COMMAND,1<<3); |
||
802 | else { |
||
803 | /* for default now... read */ |
||
804 | /*outp(BM_REG_COMMAND,1<<3);*/ |
||
805 | /* for write */ |
||
806 | outp(BM_REG_COMMAND,0); |
||
807 | } |
||
808 | |||
809 | /* clear INTR & ERROR flags */ |
||
810 | outp(BM_REG_STATUS,inp(BM_REG_STATUS)|6); |
||
811 | |||
812 | /* write command*/ |
||
813 | outp(IDE_REG_COMMAND,idereq[req].cmd); |
||
814 | |||
815 | /* start DMA */ |
||
816 | outp(BM_REG_COMMAND,inp(BM_REG_COMMAND)|1); |
||
817 | |||
818 | printk4(ideif,"F3"); |
||
819 | |||
820 | return IDE_OK; |
||
821 | } |
||
822 | |||
823 | /* |
||
824 | * |
||
825 | * PIO IN/OUT and NO_DATA commands |
||
826 | * |
||
827 | */ |
||
828 | |||
829 | /* write command*/ |
||
830 | outp(IDE_REG_COMMAND,idereq[req].cmd); |
||
831 | |||
832 | /* to wait for 400ns; I hope */ |
||
833 | #ifndef IDE_SKIPSTATUSTEST |
||
834 | inp(IDE_REG_STATUS); |
||
835 | #endif |
||
836 | |||
837 | switch (cmd2type(idereq[req].cmd)) { |
||
838 | |||
839 | /* for PIO data in commands and NODATA commands */ |
||
840 | |||
841 | case ATA_TYPE_PIOIN: |
||
842 | case ATA_TYPE_NODATA: |
||
843 | |||
844 | /* Well, the host should set the BUSY flag*/ |
||
845 | #ifndef IDE_SKIPSTATUSTEST |
||
846 | retries=RETRY; |
||
847 | while (--retries>=0) { |
||
848 | status=inp(IDE_REG_ALTSTATUS); |
||
849 | if ((status&STATUS_BUSY)!=0) break; |
||
850 | } |
||
851 | if (retries<0) return IDE_ERR_NOTBUSY; |
||
852 | #endif |
||
853 | printk4(ideif,"E1"); |
||
854 | |||
855 | return IDE_OK; |
||
856 | |||
857 | /* for PIO data out commands */ |
||
858 | |||
859 | case ATA_TYPE_PIOOUT: |
||
860 | |||
861 | for (;;) { |
||
862 | /* Well, perhaps a timeout is necessary! */ |
||
863 | status=inp(IDE_REG_ALTSTATUS); |
||
864 | #ifndef IDE_SKIPALLTEST |
||
865 | if ((status&STATUS_BUSY)!=0) break; |
||
866 | #else |
||
867 | break; |
||
868 | #endif |
||
869 | } |
||
870 | printk4(ideif,"E2"); |
||
871 | |||
872 | if ((status&STATUS_ERR)||(status&STATUS_R_FAULT)) { |
||
873 | /* an error is detected! */ |
||
874 | idereq[req].result=((status&STATUS_ERR)? |
||
875 | decode_error_result(ideif):IDE_ERR_FAULT |
||
876 | ); |
||
877 | return idereq[req].result; |
||
878 | |||
879 | } |
||
880 | if (!(status&STATUS_DRQ)) { |
||
881 | /* error, */ |
||
882 | return IDE_ERR_NODATAREQ; |
||
883 | } |
||
884 | |||
885 | /* Data I/O */ |
||
886 | ptr=(WORD*)idereq[req].buffer; |
||
887 | for (n=0;n<IDE_SECTOR_SIZE>>1;n++) |
||
888 | *ptr++=inpw(IDE_REG_DATA); |
||
889 | |||
890 | /* to wait for 400ns; I hope ;-) */ |
||
891 | #ifndef IDE_SKIPALLTEST |
||
892 | inp(IDE_REG_ALTSTATUS); |
||
893 | #endif |
||
894 | |||
895 | #ifndef IDE_SKIPALLTEST |
||
896 | status=inp(IDE_REG_ALTSTATUS); |
||
897 | if ((status&STATUS_BUSY)==0) return IDE_ERR_NOTBUSY; |
||
898 | #endif |
||
899 | |||
900 | printk4(ideif,"F2"); |
||
901 | |||
902 | return IDE_OK; |
||
903 | } |
||
904 | |||
905 | return IDE_ERR_UNKNOWN; |
||
906 | } |
||
907 | |||
908 | /* (must be 6sec for ATA specs) */ |
||
909 | #define WAITENDRESET_ELAPSE 200000l |
||
910 | |||
911 | int do_ide_softreset(int ideif) |
||
912 | { |
||
913 | unsigned long t; |
||
914 | int flag; |
||
915 | int status; |
||
916 | |||
917 | printk2(ideif,"START"); |
||
918 | |||
919 | printk2(ideif,"waiting for not busy..."); |
||
920 | /* 1 msec */ |
||
921 | flag=1; |
||
922 | t=__gettimer()+1000; |
||
923 | while (__gettimer()<t) { |
||
924 | status=inp(IDE_REG_ALTSTATUS); |
||
925 | if (!(status&STATUS_BUSY)) { flag=0; break; } |
||
926 | } |
||
927 | if (flag) { |
||
928 | printk2(ideif,"device is busy!"); |
||
929 | #ifndef IDE_FORCERESET |
||
930 | printk2(ideif,"END"); |
||
931 | return IDE_ERR_TIMEOUT; |
||
932 | #endif |
||
933 | printk2(ideif,"with FORCERESET"); |
||
934 | } else |
||
935 | printk2(ideif,"not busy"); |
||
936 | |||
937 | printk2(ideif,"soft resetting"); |
||
938 | outp(IDE_REG_DEVCTRL,DEVCTRL_SOFTRESET); |
||
939 | __delayk(5); |
||
940 | outp(IDE_REG_DEVCTRL,DEVCTRL_NORMALOP); |
||
941 | |||
942 | __delayk(2000); |
||
943 | |||
944 | printk2(ideif,"waiting for soft resetting end"); |
||
945 | /* 6sec */ |
||
946 | flag=1; |
||
947 | t=__gettimer()+WAITENDRESET_ELAPSE; |
||
948 | while (__gettimer()<t) { |
||
949 | status=inp(IDE_REG_ALTSTATUS); |
||
950 | if (!(status&STATUS_BUSY||!(status&STATUS_DRDY))) { flag=0; break; } |
||
951 | } |
||
952 | if (flag) { |
||
953 | printk2(ideif,"not ending!!"); |
||
954 | printk2(ideif,"END"); |
||
955 | return IDE_ERR_TIMEOUT; |
||
956 | } |
||
957 | printk2(ideif,"resetting end"); |
||
958 | |||
959 | printk2(ideif,"END"); |
||
960 | return IDE_OK; |
||
961 | } |
||
962 | |||
963 | /* |
||
964 | * |
||
965 | * |
||
966 | * |
||
967 | */ |
||
968 | |||
969 | /* abort per i packet */ |
||
970 | |||
971 | static int REQ_PROLOG(void) |
||
972 | { |
||
973 | int req; |
||
974 | |||
975 | req=get_idereq(); |
||
976 | if (req==NIL) |
||
977 | return IDE_ERR_TOOMUCHREQ; |
||
978 | |||
979 | /* ide[].resetonerror: |
||
980 | * |
||
981 | * used by calling thread |
||
982 | * 0 -> no soft reset on error |
||
983 | * 1 -> request a soft reset on error |
||
984 | * used by called thread (the server) |
||
985 | * 2 -> the calling thread MUST do a soft reset |
||
986 | */ |
||
987 | |||
988 | /* for safety */ |
||
989 | idereq[req].resetonerror=1; |
||
990 | |||
991 | return req; |
||
992 | } |
||
993 | |||
994 | /* elapse for a timeouted request in usec (must be 2sec for ATA spec) */ |
||
995 | #define TIMED_ELAPSE 80000l |
||
996 | |||
997 | static int __REQ_EPILOG(int ideif, int drv, int req, int timed) |
||
998 | { |
||
999 | int res,ret; |
||
1000 | //long num; |
||
1001 | |||
1002 | printk3(ideif,"START"); |
||
1003 | |||
1004 | ret=insert_idereq(ideif,drv,req); |
||
1005 | if (ret) { |
||
1006 | printk3(ideif,"activating server task"); |
||
1007 | ide_glue_send_request(ideif); |
||
1008 | } else |
||
1009 | printk3(ideif,"server task already running"); |
||
1010 | |||
1011 | if (timed) { |
||
1012 | unsigned long timer,timer2,timer3; |
||
1013 | printk3(ideif,"waiting timed server reply"); |
||
1014 | res=1; |
||
1015 | timer=__gettimer(); |
||
1016 | printk3(ideif,"AA"); |
||
1017 | assertk(timer!=0); |
||
1018 | timer+=TIMED_ELAPSE; |
||
1019 | printk3(ideif,"BB"); |
||
1020 | timer3=0; |
||
1021 | |||
1022 | /* |
||
1023 | { |
||
1024 | SYS_FLAGS f; |
||
1025 | f=kern_fsave(); |
||
1026 | kern_frestore(f); |
||
1027 | cprintf("[f=0x%x]",(int)f); |
||
1028 | } |
||
1029 | */ |
||
1030 | |||
1031 | while ((timer2=__gettimer())<timer) { |
||
1032 | |||
1033 | //cprintf("<%li>",timer2); |
||
1034 | |||
1035 | |||
1036 | //if (timer2<timer3) break; |
||
1037 | //timer3=timer2; |
||
1038 | |||
1039 | res=__b_sem_trywait(&idereq[req].wait); |
||
1040 | if (!res) break; |
||
1041 | } |
||
1042 | printk3(ideif,"CC"); |
||
1043 | if (res) { |
||
1044 | /* DANGER: if this is sent and an'interrupt occur |
||
1045 | * the reqpending assertion of the server fail |
||
1046 | */ |
||
1047 | printk3(ideif,"timer expired.. try to remove request"); |
||
1048 | ide_glue_send_request(ideif); |
||
1049 | __b_sem_wait(&idereq[req].wait); |
||
1050 | res=IDE_ERR_TIMEOUT; |
||
1051 | } else { |
||
1052 | res=idereq[req].result; |
||
1053 | printk3(ideif,"server reply ok"); |
||
1054 | } |
||
1055 | } else { |
||
1056 | printk3(ideif,"waiting server reply"); |
||
1057 | #ifdef TRACEWAIT |
||
1058 | num=exec_shadow; |
||
1059 | trc_logevent(TRC_USER1,&num); |
||
1060 | #endif |
||
1061 | __b_sem_wait(&idereq[req].wait); |
||
1062 | #ifdef TRACEWAIT |
||
1063 | trc_logevent(TRC_USER2,&num); |
||
1064 | #endif |
||
1065 | printk3(ideif,"server reply ok"); |
||
1066 | res=idereq[req].result; |
||
1067 | } |
||
1068 | free_idereq(req); |
||
1069 | |||
1070 | if (idereq[req].resetonerror==2) { |
||
1071 | printk3(ideif,"SOFT RESET"); |
||
1072 | do_ide_softreset(ideif); |
||
1073 | ret=releasequeue_idereq(ideif); |
||
1074 | if (ret) { |
||
1075 | /* there are request pending... */ |
||
1076 | ide_glue_send_request(ideif); |
||
1077 | } |
||
1078 | } |
||
1079 | |||
1080 | |||
1081 | printk3(ideif,"END"); |
||
1082 | return res; |
||
1083 | } |
||
1084 | |||
1085 | #define REQ_EPILOG(ideif,drv,req) __REQ_EPILOG(ideif,drv,req,0) |
||
1086 | #define TIMED_REQ_EPILOG(ideif,drv,req) __REQ_EPILOG(ideif,drv,req,1) |
||
1087 | |||
1088 | /**/ |
||
1089 | |||
1090 | static void fill_prologue(int req, |
||
1091 | int cmd, |
||
1092 | unsigned lsector, |
||
1093 | struct phdskinfo *pdisk) |
||
1094 | { |
||
1095 | unsigned track; |
||
1096 | |||
1097 | if (cmd==REQ_DUMMY) { |
||
1098 | idereq[req].info.sector=0; |
||
1099 | idereq[req].info.head=0; |
||
1100 | idereq[req].info.cylinder=0; |
||
1101 | idereq[req].info.nsectors=0; |
||
1102 | idereq[req].info.operation=cmd; |
||
1103 | return; |
||
1104 | } |
||
1105 | track=lsector/pdisk->pd_phgeom.sectors; |
||
1106 | idereq[req].info.sector=lsector%pdisk->pd_phgeom.sectors+1; |
||
1107 | idereq[req].info.head=track%pdisk->pd_phgeom.heads; |
||
1108 | idereq[req].info.cylinder=track/pdisk->pd_phgeom.heads; |
||
1109 | idereq[req].info.nsectors=1; |
||
1110 | idereq[req].info.operation=cmd; |
||
1111 | } |
||
1112 | |||
1113 | int ide_identify(int ideif, int id, struct ata_diskid *buffer) |
||
1114 | { |
||
1115 | int req,ret; |
||
1116 | |||
1117 | printk1(ideif,"%s start",cmd2str(ATA_IDENTIFY)); |
||
1118 | |||
1119 | req=REQ_PROLOG(); |
||
1120 | if (req<0) { |
||
1121 | printk1(ideif,"%s end=%i",cmd2str(ATA_IDENTIFY),req); |
||
1122 | return req; |
||
1123 | } |
||
1124 | |||
1125 | idereq[req].cmd=ATA_IDENTIFY; |
||
1126 | idereq[req].features=0; |
||
1127 | idereq[req].cyllow=0; |
||
1128 | idereq[req].cylhig=0; |
||
1129 | idereq[req].seccou=0; |
||
1130 | idereq[req].secnum=0; |
||
1131 | idereq[req].devhead=0xa0|((id&0x01)<<4); |
||
1132 | idereq[req].buffer=(BYTE*)buffer; |
||
1133 | idereq[req].resetonerror=0; |
||
1134 | fill_prologue(req,REQ_DUMMY,0,ide[ideif].pdisk[id]); |
||
1135 | |||
1136 | ret=TIMED_REQ_EPILOG(ideif,id,req); |
||
1137 | |||
1138 | if (ret==IDE_OK) ide_fixdiskid(buffer); |
||
1139 | |||
1140 | printk1(ideif,"%s end=%i",cmd2str(ATA_IDENTIFY),ret); |
||
1141 | return ret; |
||
1142 | } |
||
1143 | |||
1144 | int ide_pidentify(int ideif, int id, struct atapi_diskid *buffer) |
||
1145 | { |
||
1146 | int req,ret; |
||
1147 | |||
1148 | printk1(ideif,"%s start",cmd2str(ATA_PIDENTIFY)); |
||
1149 | |||
1150 | req=REQ_PROLOG(); |
||
1151 | if (req<0) { |
||
1152 | printk1(ideif,"%s end=%i",cmd2str(ATA_PIDENTIFY),req); |
||
1153 | return req; |
||
1154 | } |
||
1155 | |||
1156 | idereq[req].cmd=ATA_PIDENTIFY; |
||
1157 | idereq[req].features=0; |
||
1158 | idereq[req].cyllow=0; |
||
1159 | idereq[req].cylhig=0; |
||
1160 | idereq[req].seccou=0; |
||
1161 | idereq[req].secnum=0; |
||
1162 | idereq[req].devhead=0xa0|((id&0x01)<<4); |
||
1163 | idereq[req].buffer=(BYTE*)buffer; |
||
1164 | idereq[req].resetonerror=0; |
||
1165 | fill_prologue(req,REQ_DUMMY,0,ide[ideif].pdisk[id]); |
||
1166 | |||
1167 | ret=TIMED_REQ_EPILOG(ideif,id,req); |
||
1168 | |||
1169 | if (ret==IDE_OK) ide_fixatapidiskid(buffer); |
||
1170 | |||
1171 | printk1(ideif,"%s end=%i",cmd2str(ATA_PIDENTIFY),ret); |
||
1172 | return ret; |
||
1173 | } |
||
1174 | |||
1175 | #define IDE_READ_RETRIES 1 |
||
1176 | #define IDE_SEEK_RETRIES 1 |
||
1177 | #define IDE_WRITE_RETRIES 1 |
||
1178 | |||
1179 | int ide_read(int ideif, int id, __blkcnt_t lsector, BYTE *buffer) |
||
1180 | { |
||
1181 | int req,ret; |
||
1182 | int i; |
||
1183 | |||
1184 | printk1(ideif,"%s start",cmd2str(ATA_READ)); |
||
1185 | |||
1186 | for (i=0;i<IDE_READ_RETRIES;i++) { |
||
1187 | |||
1188 | req=REQ_PROLOG(); |
||
1189 | if (req<0) { |
||
1190 | printk1(ideif,"%s end(1)=%i",cmd2str(ATA_READ),req); |
||
1191 | return req; |
||
1192 | } |
||
1193 | |||
1194 | idereq[req].cmd=ATA_READ; |
||
1195 | assertk(ide[ideif].info[id].use_dma==0); |
||
1196 | if (ide[ideif].info[id].use_bm_dma) idereq[req].cmd=ATA_DMAREAD; |
||
1197 | lba2chs(ideif,id,lsector,req); |
||
1198 | idereq[req].features=0; |
||
1199 | idereq[req].seccou=1; |
||
1200 | idereq[req].buffer=buffer; |
||
1201 | idereq[req].resetonerror=1; |
||
1202 | fill_prologue(req,REQ_READ,lsector,ide[ideif].pdisk[id]); |
||
1203 | |||
1204 | ret=REQ_EPILOG(ideif,id,req); |
||
1205 | if (ret==IDE_OK) break; |
||
1206 | if (i!=0) printk1(ideif,"%s retry",cmd2str(ATA_READ)); |
||
1207 | } |
||
1208 | printk1(ideif,"%s end(2)=%i",cmd2str(ATA_READ),ret); |
||
1209 | return ret; |
||
1210 | } |
||
1211 | |||
1212 | int ide_seek(int ideif, int id, __blkcnt_t lsector) |
||
1213 | { |
||
1214 | int req,ret; |
||
1215 | int i; |
||
1216 | |||
1217 | printk1(ideif,"%s start",cmd2str(ATA_SEEK)); |
||
1218 | |||
1219 | for (i=0;i<IDE_SEEK_RETRIES;i++) { |
||
1220 | |||
1221 | req=REQ_PROLOG(); |
||
1222 | if (req<0) { |
||
1223 | printk1(ideif,"%s end=%i",cmd2str(ATA_SEEK),req); |
||
1224 | return req; |
||
1225 | } |
||
1226 | |||
1227 | idereq[req].cmd=ATA_SEEK; |
||
1228 | lba2chs(ideif,id,lsector,req); |
||
1229 | idereq[req].features=0; |
||
1230 | idereq[req].seccou=0; |
||
1231 | idereq[req].buffer=NULL; |
||
1232 | idereq[req].resetonerror=1; |
||
1233 | fill_prologue(req,REQ_SEEK,lsector,ide[ideif].pdisk[id]); |
||
1234 | |||
1235 | ret=REQ_EPILOG(ideif,id,req); |
||
1236 | if (ret==IDE_OK) break; |
||
1237 | if (i!=0) printk1(ideif,"%s retry",cmd2str(ATA_SEEK)); |
||
1238 | } |
||
1239 | printk1(ideif,"%s end=%i",cmd2str(ATA_SEEK),ret); |
||
1240 | return ret; |
||
1241 | } |
||
1242 | |||
1243 | int ide_enablelookahead(int ideif, int id) |
||
1244 | { |
||
1245 | int req,ret; |
||
1246 | |||
1247 | #ifndef IDE_ENABLESETFEATURES |
||
1248 | printk(KERN_NOTICE "ide command 'enable look-ahead' not yet implementated"); |
||
1249 | return IDE_ERR_UNKNOWN; |
||
1250 | #endif |
||
1251 | |||
1252 | printk1(ideif,"%s start (enable look a head)",cmd2str(ATA_SETFEATURE)); |
||
1253 | |||
1254 | req=REQ_PROLOG(); |
||
1255 | if (req<0) { |
||
1256 | printk1(ideif,"%s end=%i",cmd2str(ATA_SETFEATURE),req); |
||
1257 | return req; |
||
1258 | } |
||
1259 | |||
1260 | idereq[req].cmd=ATA_SETFEATURE; |
||
1261 | idereq[req].features=ATA_FEATURE_ENABLELOOKAHEAD; |
||
1262 | idereq[req].cyllow=0; |
||
1263 | idereq[req].cylhig=0; |
||
1264 | idereq[req].seccou=0; |
||
1265 | idereq[req].secnum=0; |
||
1266 | idereq[req].devhead=((id&0x01)<<4); |
||
1267 | idereq[req].buffer=NULL; |
||
1268 | idereq[req].resetonerror=1; |
||
1269 | fill_prologue(req,REQ_DUMMY,0,ide[ideif].pdisk[id]); |
||
1270 | |||
1271 | ret=REQ_EPILOG(ideif,id,req); |
||
1272 | |||
1273 | //ide_dump_interface_status(ideif); |
||
1274 | |||
1275 | __delayk(5); |
||
1276 | outp(IDE_REG_DEVCTRL,DEVCTRL_NORMALOP); |
||
1277 | |||
1278 | printk1(ideif,"%s end=%i",cmd2str(ATA_SETFEATURE),ret); |
||
1279 | return ret; |
||
1280 | } |
||
1281 | |||
1282 | int ide_disablelookahead(int ideif, int id) |
||
1283 | { |
||
1284 | int req,ret; |
||
1285 | |||
1286 | #ifndef IDE_ENABLESETFEATURES |
||
1287 | printk(KERN_NOTICE "ide command 'disable look-ahead' not yet implementated"); |
||
1288 | return IDE_ERR_UNKNOWN; |
||
1289 | #endif |
||
1290 | |||
1291 | printk1(ideif,"%s start (enable look a head)",cmd2str(ATA_SETFEATURE)); |
||
1292 | |||
1293 | req=REQ_PROLOG(); |
||
1294 | if (req<0) { |
||
1295 | printk1(ideif,"%s end=%i",cmd2str(ATA_SETFEATURE),req); |
||
1296 | return req; |
||
1297 | } |
||
1298 | |||
1299 | idereq[req].cmd=ATA_SETFEATURE; |
||
1300 | idereq[req].features=ATA_FEATURE_DISABLELOOKAHEAD; |
||
1301 | idereq[req].cyllow=0; |
||
1302 | idereq[req].cylhig=0; |
||
1303 | idereq[req].seccou=0; |
||
1304 | idereq[req].secnum=0; |
||
1305 | idereq[req].devhead=((id&0x01)<<4); |
||
1306 | idereq[req].buffer=NULL; |
||
1307 | idereq[req].resetonerror=1; |
||
1308 | fill_prologue(req,REQ_DUMMY,0,ide[ideif].pdisk[id]); |
||
1309 | |||
1310 | ret=REQ_EPILOG(ideif,id,req); |
||
1311 | |||
1312 | printk1(ideif,"%s end=%i",cmd2str(ATA_SETFEATURE),ret); |
||
1313 | return ret; |
||
1314 | } |
||
1315 | |||
1316 | int ide_settransfertmode(int ideif, int id, int mode) |
||
1317 | { |
||
1318 | int req,ret; |
||
1319 | |||
1320 | #ifndef IDE_ENABLESETFEATURES |
||
1321 | printk(KERN_NOTICE "ide command 'set transfert mode' not yet implementated"); |
||
1322 | return IDE_ERR_UNKNOWN; |
||
1323 | #endif |
||
1324 | |||
1325 | printk1(ideif,"%s start (set transfert mode)",cmd2str(ATA_SETFEATURE)); |
||
1326 | |||
1327 | req=REQ_PROLOG(); |
||
1328 | if (req<0) { |
||
1329 | printk1(ideif,"%s end=%i",cmd2str(ATA_SETFEATURE),req); |
||
1330 | return req; |
||
1331 | } |
||
1332 | |||
1333 | idereq[req].cmd=ATA_SETFEATURE; |
||
1334 | idereq[req].features=ATA_FEATURE_SETTRANSFERTMODE; |
||
1335 | idereq[req].cyllow=0; |
||
1336 | idereq[req].cylhig=0; |
||
1337 | idereq[req].seccou=mode; |
||
1338 | idereq[req].secnum=0; |
||
1339 | idereq[req].devhead=((id&0x01)<<4); |
||
1340 | idereq[req].buffer=NULL; |
||
1341 | idereq[req].resetonerror=1; |
||
1342 | fill_prologue(req,REQ_DUMMY,0,ide[ideif].pdisk[id]); |
||
1343 | |||
1344 | ret=REQ_EPILOG(ideif,id,req); |
||
1345 | |||
1346 | ide_dump_interface_status(ideif); |
||
1347 | |||
1348 | printk1(ideif,"%s end=%i",cmd2str(ATA_SETFEATURE),ret); |
||
1349 | return ret; |
||
1350 | } |
||
1351 | |||
1352 | int ide_write(int ideif, int id, __blkcnt_t lsector, BYTE *buffer) |
||
1353 | { |
||
1354 | int req,ret; |
||
1355 | int i; |
||
1356 | |||
1357 | printk1(ideif,"%s start",cmd2str(ATA_WRITE)); |
||
1358 | |||
1359 | for (i=0;i<IDE_WRITE_RETRIES;i++) { |
||
1360 | |||
1361 | req=REQ_PROLOG(); |
||
1362 | if (req<0) { |
||
1363 | printk1(ideif,"%s end=%i",cmd2str(ATA_WRITE),req); |
||
1364 | return req; |
||
1365 | } |
||
1366 | |||
1367 | idereq[req].cmd=ATA_WRITE; |
||
1368 | assertk(ide[ideif].info[id].use_dma==0); |
||
1369 | if (ide[ideif].info[id].use_bm_dma) idereq[req].cmd=ATA_DMAWRITE; |
||
1370 | else { |
||
1371 | panic("there is no support for polled write (only DMA allowed)!"); |
||
1372 | } |
||
1373 | lba2chs(ideif,id,lsector,req); |
||
1374 | idereq[req].features=0; |
||
1375 | idereq[req].seccou=1; |
||
1376 | idereq[req].buffer=buffer; |
||
1377 | idereq[req].resetonerror=1; |
||
1378 | fill_prologue(req,REQ_WRITE,lsector,ide[ideif].pdisk[id]); |
||
1379 | |||
1380 | ret=REQ_EPILOG(ideif,id,req); |
||
1381 | if (ret==IDE_OK) break; |
||
1382 | if (i!=0) printk1(ideif,"%s retry",cmd2str(ATA_WRITE)); |
||
1383 | } |
||
1384 | printk1(ideif,"%s end=%i",cmd2str(ATA_WRITE),ret); |
||
1385 | return ret; |
||
1386 | } |
||
1387 | |||
1388 | /**/ |
||
1389 | |||
1390 | void ide_service_request(int ideif) |
||
1391 | { |
||
1392 | static int reqpending=0; |
||
1393 | BYTE status,dma_status; |
||
1394 | int res=0,req=0; |
||
1395 | int n; |
||
1396 | |||
1397 | printk0(ideif,"ACTIVATED"); |
||
1398 | //assertk(ide[ideif].reqhead!=NIL); |
||
1399 | |||
1400 | if (!reqpending) { |
||
1401 | printk0(ideif,"doing a new request"); |
||
1402 | reqpending=1; |
||
1403 | goto DO_REQUEST; |
||
1404 | } |
||
1405 | |||
1406 | printk0(ideif,"start to serve %s request",cmd2str(idereq[req].cmd)); |
||
1407 | status=inp(IDE_REG_STATUS); |
||
1408 | //req=ide[ideif].reqhead; |
||
1409 | req=actual_idereq(ideif); |
||
1410 | |||
1411 | /* |
||
1412 | if (req==NIL) { |
||
1413 | printk(KERN_INFO "unaspceted INTR catch"); |
||
1414 | continue; |
||
1415 | } |
||
1416 | */ |
||
1417 | |||
1418 | if (status&STATUS_BUSY||status&STATUS_ERR) { |
||
1419 | idereq[req].cmd=0; |
||
1420 | /* to FIX! */ |
||
1421 | } |
||
1422 | |||
1423 | switch (idereq[req].cmd) { |
||
1424 | |||
1425 | /* |
||
1426 | * DMA COMMANDS |
||
1427 | * |
||
1428 | * DMAREAD |
||
1429 | */ |
||
1430 | |||
1431 | case ATA_DMAREAD: |
||
1432 | case ATA_DMAWRITE: |
||
1433 | /* from Linux 2.2.12 */ |
||
1434 | |||
1435 | /* stop DMA */ |
||
1436 | outp(BM_REG_COMMAND,inp(BM_REG_COMMAND)&~1); |
||
1437 | |||
1438 | /* get DMA status */ |
||
1439 | dma_status = inp(BM_REG_STATUS); |
||
1440 | |||
1441 | /* clear the INTR & ERROR bits */ |
||
1442 | outp(BM_REG_STATUS,dma_status|6); |
||
1443 | |||
1444 | /* verify good DMA status (0 -> OK)*/ |
||
1445 | dma_status=(dma_status&7)!=4; |
||
1446 | |||
1447 | if (dma_status||status&STATUS_DRQ) |
||
1448 | idereq[req].result=((status&STATUS_ERR)? |
||
1449 | decode_error_result(ideif):IDE_ERR_DMA |
||
1450 | ); |
||
1451 | else |
||
1452 | idereq[req].result=IDE_OK; |
||
1453 | break; |
||
1454 | |||
1455 | /* |
||
1456 | * NO DATA COMMANDS |
||
1457 | * |
||
1458 | * SEEK and SET FEATURE |
||
1459 | */ |
||
1460 | |||
1461 | case ATA_SEEK: |
||
1462 | case ATA_SETFEATURE: |
||
1463 | |||
1464 | if (status&STATUS_DRQ) { |
||
1465 | idereq[req].result=((status&STATUS_ERR)? |
||
1466 | decode_error_result(ideif):IDE_ERR_DATA |
||
1467 | ); |
||
1468 | } else |
||
1469 | idereq[req].result=IDE_OK; |
||
1470 | |||
1471 | break; |
||
1472 | |||
1473 | case ATA_PIDENTIFY: |
||
1474 | case ATA_IDENTIFY: |
||
1475 | case ATA_READ: |
||
1476 | |||
1477 | /* |
||
1478 | * PIO IN COMMANDS |
||
1479 | * |
||
1480 | * PIDENTIFY, IDENTIFY and READ commands |
||
1481 | */ |
||
1482 | |||
1483 | if (status&STATUS_DRQ) { |
||
1484 | WORD *ptr=(WORD*)idereq[req].buffer; |
||
1485 | for (n=0;n<IDE_SECTOR_SIZE>>1;n++) |
||
1486 | *ptr++=inpw(IDE_REG_DATA); |
||
1487 | status=inp(IDE_REG_ALTSTATUS); |
||
1488 | |||
1489 | } else { |
||
1490 | idereq[req].result=((status&STATUS_ERR)? |
||
1491 | decode_error_result(ideif):IDE_ERR_NODATA |
||
1492 | ); |
||
1493 | } |
||
1494 | status=inp(IDE_REG_STATUS); |
||
1495 | if (status&STATUS_DRQ) idereq[req].result=IDE_ERR_NODATA; /*fix*/ |
||
1496 | else idereq[req].result=IDE_OK; |
||
1497 | |||
1498 | break; |
||
1499 | |||
1500 | /* |
||
1501 | * PIO OUT COMMANDS |
||
1502 | * |
||
1503 | * WRITE command |
||
1504 | */ |
||
1505 | |||
1506 | case ATA_WRITE: |
||
1507 | /* all work is done into do_io_request() */ |
||
1508 | idereq[req].result=IDE_OK; |
||
1509 | break; |
||
1510 | |||
1511 | /* |
||
1512 | * BOH ?!? |
||
1513 | */ |
||
1514 | |||
1515 | default: |
||
1516 | /* an abort is more appropiate! */ |
||
1517 | inp(IDE_REG_ALTSTATUS); |
||
1518 | idereq[req].result=IDE_ERR_UNKNOWN; |
||
1519 | break; |
||
1520 | } |
||
1521 | |||
1522 | #ifdef IDE_OLDATAPIDELAY |
||
1523 | if (idereq[req].cmd==ATA_PIDENTIFY) { |
||
1524 | /* delay for old ATAPI device */ |
||
1525 | /* on my old cdrom a n>700 is ok */ |
||
1526 | for (n=0;n<750;n++) { |
||
1527 | status=inp(IDE_REG_ALTSTATUS); |
||
1528 | if (status&0x100) break; |
||
1529 | } |
||
1530 | } |
||
1531 | #endif |
||
1532 | |||
1533 | reqpending=remove_idereq(ideif); |
||
1534 | printk0(ideif,"end to serve request (result=%i)",idereq[req].result); |
||
1535 | __b_sem_signal(&idereq[req].wait); |
||
1536 | if (reqpending) printk0(ideif,"another request into the queue"); |
||
1537 | |||
1538 | DO_REQUEST: |
||
1539 | /* if there are requests pending... */ |
||
1540 | if (reqpending) |
||
1541 | /* loop until no request error! */ |
||
1542 | for (;;) { |
||
1543 | /* made request! */ |
||
1544 | printk0(ideif,"made new request"); |
||
1545 | res=do_io_request(ideif); |
||
1546 | if (res!=IDE_OK) { |
||
1547 | /* if request fail... */ |
||
1548 | |||
1549 | /* update result */ |
||
1550 | printk0(ideif,"new request fail (code: %i)",res); |
||
1551 | |||
1552 | //req=ide[ideif].reqhead; |
||
1553 | req=actual_idereq(ideif); |
||
1554 | idereq[req].result=res; |
||
1555 | |||
1556 | /* if "request on error" ... */ |
||
1557 | if (idereq[req].resetonerror==1) { |
||
1558 | /* request a soft error */ |
||
1559 | printk0(ideif,"ERROR: soft reset in progress.."); |
||
1560 | idereq[req].resetonerror=2; |
||
1561 | ide[ideif].errors++; |
||
1562 | /* remove request (blocking new ones) and wake up blocked thread */ |
||
1563 | reqpending=remove_idereq_blocking(ideif); |
||
1564 | __b_sem_signal(&idereq[req].wait); |
||
1565 | break; |
||
1566 | } |
||
1567 | |||
1568 | /* remove request and wake up waiting thread */ |
||
1569 | reqpending=remove_idereq(ideif); |
||
1570 | __b_sem_signal(&idereq[req].wait); |
||
1571 | |||
1572 | if (reqpending) printk0(ideif,"redoing a new request"); |
||
1573 | /* if no more request... go out of the loop! */ |
||
1574 | if (!reqpending) break; |
||
1575 | } else |
||
1576 | /* if request does not fail... */ |
||
1577 | /* go out of the loop */ |
||
1578 | printk0(ideif,"new request in progress"); |
||
1579 | break; |
||
1580 | } |
||
1581 | } |