source: branches/minix3-book/drivers/at_wini/at_wini.c050921

Last change on this file was 4, checked in by Mattia Monga, 14 years ago

Importazione sorgenti libro

File size: 53.3 KB
Line 
1/* This file contains the device dependent part of a driver for the IBM-AT
2 * winchester controller. Written by Adri Koppes.
3 *
4 * The file contains one entry point:
5 *
6 * at_winchester_task: main entry when system is brought up
7 *
8 * Changes:
9 * Aug 19, 2005 ata pci support, supports SATA (Ben Gras)
10 * Nov 18, 2004 moved AT disk driver to user-space (Jorrit N. Herder)
11 * Aug 20, 2004 watchdogs replaced by sync alarms (Jorrit N. Herder)
12 * Mar 23, 2000 added ATAPI CDROM support (Michael Temari)
13 * May 14, 2000 d-d/i rewrite (Kees J. Bot)
14 * Apr 13, 1992 device dependent/independent split (Kees J. Bot)
15 */
16
17#include "at_wini.h"
18#include "../libpci/pci.h"
19
20#include <minix/sysutil.h>
21#include <minix/keymap.h>
22#include <sys/ioc_disk.h>
23
24#define ATAPI_DEBUG 0 /* To debug ATAPI code. */
25
26/* I/O Ports used by winchester disk controllers. */
27
28/* Read and write registers */
29#define REG_CMD_BASE0 0x1F0 /* command base register of controller 0 */
30#define REG_CMD_BASE1 0x170 /* command base register of controller 1 */
31#define REG_CTL_BASE0 0x3F6 /* control base register of controller 0 */
32#define REG_CTL_BASE1 0x376 /* control base register of controller 1 */
33
34#define REG_DATA 0 /* data register (offset from the base reg.) */
35#define REG_PRECOMP 1 /* start of write precompensation */
36#define REG_COUNT 2 /* sectors to transfer */
37#define REG_SECTOR 3 /* sector number */
38#define REG_CYL_LO 4 /* low byte of cylinder number */
39#define REG_CYL_HI 5 /* high byte of cylinder number */
40#define REG_LDH 6 /* lba, drive and head */
41#define LDH_DEFAULT 0xA0 /* ECC enable, 512 bytes per sector */
42#define LDH_LBA 0x40 /* Use LBA addressing */
43#define ldh_init(drive) (LDH_DEFAULT | ((drive) << 4))
44
45/* Read only registers */
46#define REG_STATUS 7 /* status */
47#define STATUS_BSY 0x80 /* controller busy */
48#define STATUS_RDY 0x40 /* drive ready */
49#define STATUS_WF 0x20 /* write fault */
50#define STATUS_SC 0x10 /* seek complete (obsolete) */
51#define STATUS_DRQ 0x08 /* data transfer request */
52#define STATUS_CRD 0x04 /* corrected data */
53#define STATUS_IDX 0x02 /* index pulse */
54#define STATUS_ERR 0x01 /* error */
55#define STATUS_ADMBSY 0x100 /* administratively busy (software) */
56#define REG_ERROR 1 /* error code */
57#define ERROR_BB 0x80 /* bad block */
58#define ERROR_ECC 0x40 /* bad ecc bytes */
59#define ERROR_ID 0x10 /* id not found */
60#define ERROR_AC 0x04 /* aborted command */
61#define ERROR_TK 0x02 /* track zero error */
62#define ERROR_DM 0x01 /* no data address mark */
63
64/* Write only registers */
65#define REG_COMMAND 7 /* command */
66#define CMD_IDLE 0x00 /* for w_command: drive idle */
67#define CMD_RECALIBRATE 0x10 /* recalibrate drive */
68#define CMD_READ 0x20 /* read data */
69#define CMD_READ_EXT 0x24 /* read data (LBA48 addressed) */
70#define CMD_WRITE 0x30 /* write data */
71#define CMD_WRITE_EXT 0x34 /* write data (LBA48 addressed) */
72#define CMD_READVERIFY 0x40 /* read verify */
73#define CMD_FORMAT 0x50 /* format track */
74#define CMD_SEEK 0x70 /* seek cylinder */
75#define CMD_DIAG 0x90 /* execute device diagnostics */
76#define CMD_SPECIFY 0x91 /* specify parameters */
77#define ATA_IDENTIFY 0xEC /* identify drive */
78/* #define REG_CTL 0x206 */ /* control register */
79#define REG_CTL 0 /* control register */
80#define CTL_NORETRY 0x80 /* disable access retry */
81#define CTL_NOECC 0x40 /* disable ecc retry */
82#define CTL_EIGHTHEADS 0x08 /* more than eight heads */
83#define CTL_RESET 0x04 /* reset controller */
84#define CTL_INTDISABLE 0x02 /* disable interrupts */
85
86#if ENABLE_ATAPI
87#define ERROR_SENSE 0xF0 /* sense key mask */
88#define SENSE_NONE 0x00 /* no sense key */
89#define SENSE_RECERR 0x10 /* recovered error */
90#define SENSE_NOTRDY 0x20 /* not ready */
91#define SENSE_MEDERR 0x30 /* medium error */
92#define SENSE_HRDERR 0x40 /* hardware error */
93#define SENSE_ILRQST 0x50 /* illegal request */
94#define SENSE_UATTN 0x60 /* unit attention */
95#define SENSE_DPROT 0x70 /* data protect */
96#define SENSE_ABRT 0xb0 /* aborted command */
97#define SENSE_MISCOM 0xe0 /* miscompare */
98#define ERROR_MCR 0x08 /* media change requested */
99#define ERROR_ABRT 0x04 /* aborted command */
100#define ERROR_EOM 0x02 /* end of media detected */
101#define ERROR_ILI 0x01 /* illegal length indication */
102#define REG_FEAT 1 /* features */
103#define FEAT_OVERLAP 0x02 /* overlap */
104#define FEAT_DMA 0x01 /* dma */
105#define REG_IRR 2 /* interrupt reason register */
106#define IRR_REL 0x04 /* release */
107#define IRR_IO 0x02 /* direction for xfer */
108#define IRR_COD 0x01 /* command or data */
109#define REG_SAMTAG 3
110#define REG_CNT_LO 4 /* low byte of cylinder number */
111#define REG_CNT_HI 5 /* high byte of cylinder number */
112#define REG_DRIVE 6 /* drive select */
113#endif
114
115#define REG_STATUS 7 /* status */
116#define STATUS_BSY 0x80 /* controller busy */
117#define STATUS_DRDY 0x40 /* drive ready */
118#define STATUS_DMADF 0x20 /* dma ready/drive fault */
119#define STATUS_SRVCDSC 0x10 /* service or dsc */
120#define STATUS_DRQ 0x08 /* data transfer request */
121#define STATUS_CORR 0x04 /* correctable error occurred */
122#define STATUS_CHECK 0x01 /* check error */
123
124#ifdef ENABLE_ATAPI
125#define ATAPI_PACKETCMD 0xA0 /* packet command */
126#define ATAPI_IDENTIFY 0xA1 /* identify drive */
127#define SCSI_READ10 0x28 /* read from disk */
128#define SCSI_SENSE 0x03 /* sense request */
129
130#define CD_SECTOR_SIZE 2048 /* sector size of a CD-ROM */
131#endif /* ATAPI */
132
133/* Interrupt request lines. */
134#define NO_IRQ 0 /* no IRQ set yet */
135
136#define ATAPI_PACKETSIZE 12
137#define SENSE_PACKETSIZE 18
138
139/* Common command block */
140struct command {
141 u8_t precomp; /* REG_PRECOMP, etc. */
142 u8_t count;
143 u8_t sector;
144 u8_t cyl_lo;
145 u8_t cyl_hi;
146 u8_t ldh;
147 u8_t command;
148};
149
150/* Error codes */
151#define ERR (-1) /* general error */
152#define ERR_BAD_SECTOR (-2) /* block marked bad detected */
153
154/* Some controllers don't interrupt, the clock will wake us up. */
155#define WAKEUP (32*HZ) /* drive may be out for 31 seconds max */
156
157/* Miscellaneous. */
158#define MAX_DRIVES 8
159#define COMPAT_DRIVES 4
160#if _WORD_SIZE > 2
161#define MAX_SECS 256 /* controller can transfer this many sectors */
162#else
163#define MAX_SECS 127 /* but not to a 16 bit process */
164#endif
165#define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
166#define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE)
167#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
168#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
169#define DELAY_USECS 1000 /* controller timeout in microseconds */
170#define DELAY_TICKS 1 /* controller timeout in ticks */
171#define DEF_TIMEOUT_TICKS 300 /* controller timeout in ticks */
172#define RECOVERY_USECS 500000 /* controller recovery time in microseconds */
173#define RECOVERY_TICKS 30 /* controller recovery time in ticks */
174#define INITIALIZED 0x01 /* drive is initialized */
175#define DEAF 0x02 /* controller must be reset */
176#define SMART 0x04 /* drive supports ATA commands */
177#if ENABLE_ATAPI
178#define ATAPI 0x08 /* it is an ATAPI device */
179#else
180#define ATAPI 0 /* don't bother with ATAPI; optimise out */
181#endif
182#define IDENTIFIED 0x10 /* w_identify done successfully */
183#define IGNORING 0x20 /* w_identify failed once */
184
185/* Timeouts and max retries. */
186int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;
187int wakeup_ticks = WAKEUP;
188long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0,
189 w_lba48 = 0, atapi_debug = 0;
190
191int w_testing = 0, w_silent = 0;
192
193int w_next_drive = 0;
194
195/* Variables. */
196
197/* wini is indexed by controller first, then drive (0-3).
198 * controller 0 is always the 'compatability' ide controller, at
199 * the fixed locations, whether present or not.
200 */
201PRIVATE struct wini { /* main drive struct, one entry per drive */
202 unsigned state; /* drive state: deaf, initialized, dead */
203 unsigned w_status; /* device status register */
204 unsigned base_cmd; /* command base register */
205 unsigned base_ctl; /* control base register */
206 unsigned irq; /* interrupt request line */
207 unsigned irq_mask; /* 1 << irq */
208 unsigned irq_need_ack; /* irq needs to be acknowledged */
209 int irq_hook_id; /* id of irq hook at the kernel */
210 int lba48; /* supports lba48 */
211 unsigned lcylinders; /* logical number of cylinders (BIOS) */
212 unsigned lheads; /* logical number of heads */
213 unsigned lsectors; /* logical number of sectors per track */
214 unsigned pcylinders; /* physical number of cylinders (translated) */
215 unsigned pheads; /* physical number of heads */
216 unsigned psectors; /* physical number of sectors per track */
217 unsigned ldhpref; /* top four bytes of the LDH (head) register */
218 unsigned precomp; /* write precompensation cylinder / 4 */
219 unsigned max_count; /* max request for this drive */
220 unsigned open_ct; /* in-use count */
221 struct device part[DEV_PER_DRIVE]; /* disks and partitions */
222 struct device subpart[SUB_PER_DRIVE]; /* subpartitions */
223} wini[MAX_DRIVES], *w_wn;
224
225PRIVATE int w_device = -1;
226PRIVATE int w_controller = -1;
227PRIVATE int w_major = -1;
228PRIVATE char w_id_string[40];
229
230PRIVATE int win_tasknr; /* my task number */
231PRIVATE int w_command; /* current command in execution */
232PRIVATE u8_t w_byteval; /* used for SYS_IRQCTL */
233PRIVATE int w_drive; /* selected drive */
234PRIVATE int w_controller; /* selected controller */
235PRIVATE struct device *w_dv; /* device's base and size */
236
237FORWARD _PROTOTYPE( void init_params, (void) );
238FORWARD _PROTOTYPE( void init_drive, (struct wini *, int, int, int, int, int, int));
239FORWARD _PROTOTYPE( void init_params_pci, (int) );
240FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
241FORWARD _PROTOTYPE( struct device *w_prepare, (int dev) );
242FORWARD _PROTOTYPE( int w_identify, (void) );
243FORWARD _PROTOTYPE( char *w_name, (void) );
244FORWARD _PROTOTYPE( int w_specify, (void) );
245FORWARD _PROTOTYPE( int w_io_test, (void) );
246FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,
247 iovec_t *iov, unsigned nr_req) );
248FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
249FORWARD _PROTOTYPE( void w_need_reset, (void) );
250FORWARD _PROTOTYPE( void ack_irqs, (unsigned int) );
251FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
252FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr) );
253FORWARD _PROTOTYPE( int w_hw_int, (struct driver *dp, message *m_ptr) );
254FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
255FORWARD _PROTOTYPE( void w_timeout, (void) );
256FORWARD _PROTOTYPE( int w_reset, (void) );
257FORWARD _PROTOTYPE( void w_intr_wait, (void) );
258FORWARD _PROTOTYPE( int at_intr_wait, (void) );
259FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
260FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
261#if ENABLE_ATAPI
262FORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt) );
263FORWARD _PROTOTYPE( int atapi_intr_wait, (void) );
264FORWARD _PROTOTYPE( int atapi_open, (void) );
265FORWARD _PROTOTYPE( void atapi_close, (void) );
266FORWARD _PROTOTYPE( int atapi_transfer, (int proc_nr, int opcode,
267 off_t position, iovec_t *iov, unsigned nr_req) );
268#endif
269
270/* Entry points to this driver. */
271PRIVATE struct driver w_dtab = {
272 w_name, /* current device's name */
273 w_do_open, /* open or mount request, initialize device */
274 w_do_close, /* release device */
275 do_diocntl, /* get or set a partition's geometry */
276 w_prepare, /* prepare for I/O on a given minor device */
277 w_transfer, /* do the I/O */
278 nop_cleanup, /* nothing to clean up */
279 w_geometry, /* tell the geometry of the disk */
280 nop_signal, /* no cleanup needed on shutdown */
281 nop_alarm, /* ignore leftover alarms */
282 nop_cancel, /* ignore CANCELs */
283 nop_select, /* ignore selects */
284 w_other, /* catch-all for unrecognized commands and ioctls */
285 w_hw_int /* leftover hardware interrupts */
286};
287
288/*===========================================================================*
289 * at_winchester_task *
290 *===========================================================================*/
291PUBLIC int main()
292{
293/* Set special disk parameters then call the generic main loop. */
294 init_params();
295 driver_task(&w_dtab);
296 return(OK);
297}
298
299/*===========================================================================*
300 * init_params *
301 *===========================================================================*/
302PRIVATE void init_params()
303{
304/* This routine is called at startup to initialize the drive parameters. */
305
306 u16_t parv[2];
307 unsigned int vector, size;
308 int drive, nr_drives;
309 struct wini *wn;
310 u8_t params[16];
311 int s;
312
313 /* Boot variables. */
314 env_parse("ata_std_timeout", "d", 0, &w_standard_timeouts, 0, 1);
315 env_parse("ata_pci_debug", "d", 0, &w_pci_debug, 0, 1);
316 env_parse("ata_instance", "d", 0, &w_instance, 0, 8);
317 env_parse("ata_lba48", "d", 0, &w_lba48, 0, 1);
318 env_parse("atapi_debug", "d", 0, &atapi_debug, 0, 1);
319
320 if (w_instance == 0) {
321 /* Get the number of drives from the BIOS data area */
322 if ((s=sys_vircopy(SELF, BIOS_SEG, NR_HD_DRIVES_ADDR,
323 SELF, D, (vir_bytes) params, NR_HD_DRIVES_SIZE)) != OK)
324 panic(w_name(), "Couldn't read BIOS", s);
325 if ((nr_drives = params[0]) > 2) nr_drives = 2;
326
327 for (drive = 0, wn = wini; drive < COMPAT_DRIVES; drive++, wn++) {
328 if (drive < nr_drives) {
329 /* Copy the BIOS parameter vector */
330 vector = (drive == 0) ? BIOS_HD0_PARAMS_ADDR:BIOS_HD1_PARAMS_ADDR;
331 size = (drive == 0) ? BIOS_HD0_PARAMS_SIZE:BIOS_HD1_PARAMS_SIZE;
332 if ((s=sys_vircopy(SELF, BIOS_SEG, vector,
333 SELF, D, (vir_bytes) parv, size)) != OK)
334 panic(w_name(), "Couldn't read BIOS", s);
335
336 /* Calculate the address of the parameters and copy them */
337 if ((s=sys_vircopy(
338 SELF, BIOS_SEG, hclick_to_physb(parv[1]) + parv[0],
339 SELF, D, (phys_bytes) params, 16L))!=OK)
340 panic(w_name(),"Couldn't copy parameters", s);
341
342 /* Copy the parameters to the structures of the drive */
343 wn->lcylinders = bp_cylinders(params);
344 wn->lheads = bp_heads(params);
345 wn->lsectors = bp_sectors(params);
346 wn->precomp = bp_precomp(params) >> 2;
347 }
348
349 /* Fill in non-BIOS parameters. */
350 init_drive(wn,
351 drive < 2 ? REG_CMD_BASE0 : REG_CMD_BASE1,
352 drive < 2 ? REG_CTL_BASE0 : REG_CTL_BASE1,
353 NO_IRQ, 0, 0, drive);
354 w_next_drive++;
355 }
356 }
357
358 /* Look for controllers on the pci bus. Skip none the first instance,
359 * skip one and then 2 for every instance, for every next instance.
360 */
361 if (w_instance == 0)
362 init_params_pci(0);
363 else
364 init_params_pci(w_instance*2-1);
365
366}
367
368#define ATA_IF_NOTCOMPAT1 (1L << 0)
369#define ATA_IF_NOTCOMPAT2 (1L << 2)
370
371/*===========================================================================*
372 * init_drive *
373 *===========================================================================*/
374PRIVATE void init_drive(struct wini *w, int base_cmd, int base_ctl, int irq, int ack, int hook, int drive)
375{
376 w->state = 0;
377 w->w_status = 0;
378 w->base_cmd = base_cmd;
379 w->base_ctl = base_ctl;
380 w->irq = irq;
381 w->irq_mask = 1 << irq;
382 w->irq_need_ack = ack;
383 w->irq_hook_id = hook;
384 w->ldhpref = ldh_init(drive);
385 w->max_count = MAX_SECS << SECTOR_SHIFT;
386 w->lba48 = 0;
387}
388
389/*===========================================================================*
390 * init_params_pci *
391 *===========================================================================*/
392PRIVATE void init_params_pci(int skip)
393{
394 int r, devind, drive;
395 u16_t vid, did;
396 pci_init();
397 for(drive = w_next_drive; drive < MAX_DRIVES; drive++)
398 wini[drive].state = IGNORING;
399 for(r = pci_first_dev(&devind, &vid, &did);
400 r != 0 && w_next_drive < MAX_DRIVES; r = pci_next_dev(&devind, &vid, &did)) {
401 int interface, irq, irq_hook;
402 /* Base class must be 01h (mass storage), subclass must
403 * be 01h (ATA).
404 */
405 if (pci_attr_r8(devind, PCI_BCR) != 0x01 ||
406 pci_attr_r8(devind, PCI_SCR) != 0x01) {
407 continue;
408 }
409 /* Found a controller.
410 * Programming interface register tells us more.
411 */
412 interface = pci_attr_r8(devind, PCI_PIFR);
413 irq = pci_attr_r8(devind, PCI_ILR);
414
415 /* Any non-compat drives? */
416 if (interface & (ATA_IF_NOTCOMPAT1 | ATA_IF_NOTCOMPAT2)) {
417 int s;
418 irq_hook = irq;
419 if (skip > 0) {
420 if (w_pci_debug) printf("atapci skipping controller (remain %d)\n", skip);
421 skip--;
422 continue;
423 }
424 if ((s=sys_irqsetpolicy(irq, 0, &irq_hook)) != OK) {
425 printf("atapci: couldn't set IRQ policy %d\n", irq);
426 continue;
427 }
428 if ((s=sys_irqenable(&irq_hook)) != OK) {
429 printf("atapci: couldn't enable IRQ line %d\n", irq);
430 continue;
431 }
432 } else {
433 /* If not.. this is not the ata-pci controller we're
434 * looking for.
435 */
436 if (w_pci_debug) printf("atapci skipping compatability controller\n");
437 continue;
438 }
439
440 /* Primary channel not in compatability mode? */
441 if (interface & ATA_IF_NOTCOMPAT1) {
442 u32_t base_cmd, base_ctl;
443 base_cmd = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
444 base_ctl = pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0;
445 if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
446 init_drive(&wini[w_next_drive],
447 base_cmd, base_ctl, irq, 1, irq_hook, 0);
448 init_drive(&wini[w_next_drive+1],
449 base_cmd, base_ctl, irq, 1, irq_hook, 1);
450 if (w_pci_debug)
451 printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq);
452 } else printf("atapci: ignored drives on primary channel, base %x\n", base_cmd);
453 }
454
455 /* Secondary channel not in compatability mode? */
456 if (interface & ATA_IF_NOTCOMPAT2) {
457 u32_t base_cmd, base_ctl;
458 base_cmd = pci_attr_r32(devind, PCI_BAR_3) & 0xffffffe0;
459 base_ctl = pci_attr_r32(devind, PCI_BAR_4) & 0xffffffe0;
460 if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
461 init_drive(&wini[w_next_drive+2],
462 base_cmd, base_ctl, irq, 1, irq_hook, 2);
463 init_drive(&wini[w_next_drive+3],
464 base_cmd, base_ctl, irq, 1, irq_hook, 3);
465 if (w_pci_debug)
466 printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq);
467 } else printf("atapci: ignored drives on secondary channel, base %x\n", base_cmd);
468 }
469 w_next_drive += 4;
470 }
471}
472
473/*===========================================================================*
474 * w_do_open *
475 *===========================================================================*/
476PRIVATE int w_do_open(dp, m_ptr)
477struct driver *dp;
478message *m_ptr;
479{
480/* Device open: Initialize the controller and read the partition table. */
481
482 struct wini *wn;
483
484 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
485
486 wn = w_wn;
487
488 /* If we've probed it before and it failed, don't probe it again. */
489 if (wn->state & IGNORING) return ENXIO;
490
491 /* If we haven't identified it yet, or it's gone deaf,
492 * (re-)identify it.
493 */
494 if (!(wn->state & IDENTIFIED) || (wn->state & DEAF)) {
495 /* Try to identify the device. */
496 if (w_identify() != OK) {
497#if VERBOSE
498 printf("%s: probe failed\n", w_name());
499#endif
500 if (wn->state & DEAF) w_reset();
501 wn->state = IGNORING;
502 return(ENXIO);
503 }
504 /* Do a test transaction unless it's a CD drive (then
505 * we can believe the controller, and a test may fail
506 * due to no CD being in the drive). If it fails, ignore
507 * the device forever.
508 */
509 if (!(wn->state & ATAPI) && w_io_test() != OK) {
510 wn->state |= IGNORING;
511 return(ENXIO);
512 }
513
514#if VERBOSE
515 printf("%s: AT driver detected ", w_name());
516 if (wn->state & (SMART|ATAPI)) {
517 printf("%.40s\n", w_id_string);
518 } else {
519 printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors);
520 }
521#endif
522 }
523
524#if ENABLE_ATAPI
525 if ((wn->state & ATAPI) && (m_ptr->COUNT & W_BIT))
526 return(EACCES);
527#endif
528
529 /* If it's not an ATAPI device, then don't open with RO_BIT. */
530 if (!(wn->state & ATAPI) && (m_ptr->COUNT & RO_BIT)) return EACCES;
531
532 /* Partition the drive if it's being opened for the first time,
533 * or being opened after being closed.
534 */
535 if (wn->open_ct == 0) {
536#if ENABLE_ATAPI
537 if (wn->state & ATAPI) {
538 int r;
539 if ((r = atapi_open()) != OK) return(r);
540 }
541#endif
542
543 /* Partition the disk. */
544 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, wn->state & ATAPI);
545 }
546 wn->open_ct++;
547 return(OK);
548}
549
550/*===========================================================================*
551 * w_prepare *
552 *===========================================================================*/
553PRIVATE struct device *w_prepare(int device)
554{
555/* Prepare for I/O on a device. */
556struct wini *prev_wn;
557prev_wn = w_wn;
558 w_device = device;
559
560 if (device < NR_MINORS) { /* d0, d0p[0-3], d1, ... */
561 w_drive = device / DEV_PER_DRIVE; /* save drive number */
562 w_wn = &wini[w_drive];
563 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
564 } else
565 if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/
566 w_drive = device / SUB_PER_DRIVE;
567 w_wn = &wini[w_drive];
568 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
569 } else {
570 w_device = -1;
571 return(NIL_DEV);
572 }
573 return(w_dv);
574}
575
576/*===========================================================================*
577 * w_identify *
578 *===========================================================================*/
579PRIVATE int w_identify()
580{
581/* Find out if a device exists, if it is an old AT disk, or a newer ATA
582 * drive, a removable media device, etc.
583 */
584
585 struct wini *wn = w_wn;
586 struct command cmd;
587 int i, s;
588 unsigned long size;
589#define id_byte(n) (&tmp_buf[2 * (n)])
590#define id_word(n) (((u16_t) id_byte(n)[0] << 0) \
591 |((u16_t) id_byte(n)[1] << 8))
592#define id_longword(n) (((u32_t) id_byte(n)[0] << 0) \
593 |((u32_t) id_byte(n)[1] << 8) \
594 |((u32_t) id_byte(n)[2] << 16) \
595 |((u32_t) id_byte(n)[3] << 24))
596
597 /* Try to identify the device. */
598 cmd.ldh = wn->ldhpref;
599 cmd.command = ATA_IDENTIFY;
600 if (com_simple(&cmd) == OK) {
601 /* This is an ATA device. */
602 wn->state |= SMART;
603
604 /* Device information. */
605 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
606 panic(w_name(),"Call to sys_insw() failed", s);
607
608 /* Why are the strings byte swapped??? */
609 for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
610
611 /* Preferred CHS translation mode. */
612 wn->pcylinders = id_word(1);
613 wn->pheads = id_word(3);
614 wn->psectors = id_word(6);
615 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
616
617 if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
618 /* Drive is LBA capable and is big enough to trust it to
619 * not make a mess of it.
620 */
621 wn->ldhpref |= LDH_LBA;
622 size = id_longword(60);
623
624 if (w_lba48 && ((id_word(83)) & (1L << 10))) {
625 /* Drive is LBA48 capable (and LBA48 is turned on). */
626 if (id_word(102) || id_word(103)) {
627 /* If no. of sectors doesn't fit in 32 bits,
628 * trunacte to this. So it's LBA32 for now.
629 * This can still address devices up to 2TB
630 * though.
631 */
632 size = ULONG_MAX;
633 } else {
634 /* Actual number of sectors fits in 32 bits. */
635 size = id_longword(100);
636 }
637
638 wn->lba48 = 1;
639 }
640 }
641
642 if (wn->lcylinders == 0) {
643 /* No BIOS parameters? Then make some up. */
644 wn->lcylinders = wn->pcylinders;
645 wn->lheads = wn->pheads;
646 wn->lsectors = wn->psectors;
647 while (wn->lcylinders > 1024) {
648 wn->lheads *= 2;
649 wn->lcylinders /= 2;
650 }
651 }
652#if ENABLE_ATAPI
653 } else
654 if (cmd.command = ATAPI_IDENTIFY, com_simple(&cmd) == OK) {
655 /* An ATAPI device. */
656 wn->state |= ATAPI;
657
658 /* Device information. */
659 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, 512)) != OK)
660 panic(w_name(),"Call to sys_insw() failed", s);
661
662 /* Why are the strings byte swapped??? */
663 for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
664
665 size = 0; /* Size set later. */
666#endif
667 } else {
668 /* Not an ATA device; no translations, no special features. Don't
669 * touch it unless the BIOS knows about it.
670 */
671 if (wn->lcylinders == 0) { return(ERR); } /* no BIOS parameters */
672 wn->pcylinders = wn->lcylinders;
673 wn->pheads = wn->lheads;
674 wn->psectors = wn->lsectors;
675 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
676 }
677
678 /* Size of the whole drive */
679 wn->part[0].dv_size = mul64u(size, SECTOR_SIZE);
680
681 /* Reset/calibrate (where necessary) */
682 if (w_specify() != OK && w_specify() != OK) {
683 return(ERR);
684 }
685
686 if (wn->irq == NO_IRQ) {
687 /* Everything looks OK; register IRQ so we can stop polling. */
688 wn->irq = w_drive < 2 ? AT_WINI_0_IRQ : AT_WINI_1_IRQ;
689 wn->irq_hook_id = wn->irq; /* id to be returned if interrupt occurs */
690 if ((s=sys_irqsetpolicy(wn->irq, IRQ_REENABLE, &wn->irq_hook_id)) != OK)
691 panic(w_name(), "couldn't set IRQ policy", s);
692 if ((s=sys_irqenable(&wn->irq_hook_id)) != OK)
693 panic(w_name(), "couldn't enable IRQ line", s);
694 }
695 wn->state |= IDENTIFIED;
696 return(OK);
697}
698
699/*===========================================================================*
700 * w_name *
701 *===========================================================================*/
702PRIVATE char *w_name()
703{
704/* Return a name for the current device. */
705 static char name[] = "AT-D0";
706
707 name[4] = '0' + w_drive;
708 return name;
709}
710
711/*===========================================================================*
712 * w_io_test *
713 *===========================================================================*/
714PRIVATE int w_io_test(void)
715{
716 int r, save_dev;
717 int save_timeout, save_errors, save_wakeup;
718 iovec_t iov;
719#ifdef CD_SECTOR_SIZE
720 static char buf[CD_SECTOR_SIZE];
721#else
722 static char buf[SECTOR_SIZE];
723#endif
724
725 iov.iov_addr = (vir_bytes) buf;
726 iov.iov_size = sizeof(buf);
727 save_dev = w_device;
728
729 /* Reduce timeout values for this test transaction. */
730 save_timeout = timeout_ticks;
731 save_errors = max_errors;
732 save_wakeup = wakeup_ticks;
733
734 if (!w_standard_timeouts) {
735 timeout_ticks = HZ * 4;
736 wakeup_ticks = HZ * 6;
737 max_errors = 3;
738 }
739
740 w_testing = 1;
741
742 /* Try I/O on the actual drive (not any (sub)partition). */
743 if (w_prepare(w_drive * DEV_PER_DRIVE) == NIL_DEV)
744 panic(w_name(), "Couldn't switch devices", NO_NUM);
745
746 r = w_transfer(SELF, DEV_GATHER, 0, &iov, 1);
747
748 /* Switch back. */
749 if (w_prepare(save_dev) == NIL_DEV)
750 panic(w_name(), "Couldn't switch back devices", NO_NUM);
751
752 /* Restore parameters. */
753 timeout_ticks = save_timeout;
754 max_errors = save_errors;
755 wakeup_ticks = save_wakeup;
756 w_testing = 0;
757
758 /* Test if everything worked. */
759 if (r != OK || iov.iov_size != 0) {
760 return ERR;
761 }
762
763 /* Everything worked. */
764
765 return OK;
766}
767
768/*===========================================================================*
769 * w_specify *
770 *===========================================================================*/
771PRIVATE int w_specify()
772{
773/* Routine to initialize the drive after boot or when a reset is needed. */
774
775 struct wini *wn = w_wn;
776 struct command cmd;
777
778 if ((wn->state & DEAF) && w_reset() != OK) {
779 return(ERR);
780 }
781
782 if (!(wn->state & ATAPI)) {
783 /* Specify parameters: precompensation, number of heads and sectors. */
784 cmd.precomp = wn->precomp;
785 cmd.count = wn->psectors;
786 cmd.ldh = w_wn->ldhpref | (wn->pheads - 1);
787 cmd.command = CMD_SPECIFY; /* Specify some parameters */
788
789 /* Output command block and see if controller accepts the parameters. */
790 if (com_simple(&cmd) != OK) return(ERR);
791
792 if (!(wn->state & SMART)) {
793 /* Calibrate an old disk. */
794 cmd.sector = 0;
795 cmd.cyl_lo = 0;
796 cmd.cyl_hi = 0;
797 cmd.ldh = w_wn->ldhpref;
798 cmd.command = CMD_RECALIBRATE;
799
800 if (com_simple(&cmd) != OK) return(ERR);
801 }
802 }
803 wn->state |= INITIALIZED;
804 return(OK);
805}
806
807/*===========================================================================*
808 * do_transfer *
809 *===========================================================================*/
810PRIVATE int do_transfer(struct wini *wn, unsigned int precomp, unsigned int count,
811 unsigned int sector, unsigned int opcode)
812{
813 struct command cmd;
814 unsigned secspcyl = wn->pheads * wn->psectors;
815
816 cmd.precomp = precomp;
817 cmd.count = count;
818 cmd.command = opcode == DEV_SCATTER ? CMD_WRITE : CMD_READ;
819 /*
820 if (w_lba48 && wn->lba48) {
821 } else */
822 if (wn->ldhpref & LDH_LBA) {
823 cmd.sector = (sector >> 0) & 0xFF;
824 cmd.cyl_lo = (sector >> 8) & 0xFF;
825 cmd.cyl_hi = (sector >> 16) & 0xFF;
826 cmd.ldh = wn->ldhpref | ((sector >> 24) & 0xF);
827 } else {
828 int cylinder, head, sec;
829 cylinder = sector / secspcyl;
830 head = (sector % secspcyl) / wn->psectors;
831 sec = sector % wn->psectors;
832 cmd.sector = sec + 1;
833 cmd.cyl_lo = cylinder & BYTE;
834 cmd.cyl_hi = (cylinder >> 8) & BYTE;
835 cmd.ldh = wn->ldhpref | head;
836 }
837
838 return com_out(&cmd);
839}
840
841/*===========================================================================*
842 * w_transfer *
843 *===========================================================================*/
844PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)
845int proc_nr; /* process doing the request */
846int opcode; /* DEV_GATHER or DEV_SCATTER */
847off_t position; /* offset on device to read or write */
848iovec_t *iov; /* pointer to read or write request vector */
849unsigned nr_req; /* length of request vector */
850{
851 struct wini *wn = w_wn;
852 iovec_t *iop, *iov_end = iov + nr_req;
853 int r, s, errors;
854 unsigned long block;
855 unsigned long dv_size = cv64ul(w_dv->dv_size);
856 unsigned cylinder, head, sector, nbytes;
857
858#if ENABLE_ATAPI
859 if (w_wn->state & ATAPI) {
860 return atapi_transfer(proc_nr, opcode, position, iov, nr_req);
861 }
862#endif
863
864
865
866 /* Check disk address. */
867 if ((position & SECTOR_MASK) != 0) return(EINVAL);
868
869 errors = 0;
870
871 while (nr_req > 0) {
872 /* How many bytes to transfer? */
873 nbytes = 0;
874 for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
875 if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
876
877 /* Which block on disk and how close to EOF? */
878 if (position >= dv_size) return(OK); /* At EOF */
879 if (position + nbytes > dv_size) nbytes = dv_size - position;
880 block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE);
881
882 if (nbytes >= wn->max_count) {
883 /* The drive can't do more then max_count at once. */
884 nbytes = wn->max_count;
885 }
886
887 /* First check to see if a reinitialization is needed. */
888 if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
889
890 /* Tell the controller to transfer nbytes bytes. */
891 r = do_transfer(wn, wn->precomp, ((nbytes >> SECTOR_SHIFT) & BYTE),
892 block, opcode);
893
894 while (r == OK && nbytes > 0) {
895 /* For each sector, wait for an interrupt and fetch the data
896 * (read), or supply data to the controller and wait for an
897 * interrupt (write).
898 */
899
900 if (opcode == DEV_GATHER) {
901 /* First an interrupt, then data. */
902 if ((r = at_intr_wait()) != OK) {
903 /* An error, send data to the bit bucket. */
904 if (w_wn->w_status & STATUS_DRQ) {
905 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
906 panic(w_name(),"Call to sys_insw() failed", s);
907 }
908 break;
909 }
910 }
911
912 /* Wait for data transfer requested. */
913 if (!w_waitfor(STATUS_DRQ, STATUS_DRQ)) { r = ERR; break; }
914
915 /* Copy bytes to or from the device's buffer. */
916 if (opcode == DEV_GATHER) {
917 if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK)
918 panic(w_name(),"Call to sys_insw() failed", s);
919 } else {
920 if ((s=sys_outsw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK)
921 panic(w_name(),"Call to sys_insw() failed", s);
922
923 /* Data sent, wait for an interrupt. */
924 if ((r = at_intr_wait()) != OK) break;
925 }
926
927 /* Book the bytes successfully transferred. */
928 nbytes -= SECTOR_SIZE;
929 position += SECTOR_SIZE;
930 iov->iov_addr += SECTOR_SIZE;
931 if ((iov->iov_size -= SECTOR_SIZE) == 0) { iov++; nr_req--; }
932 }
933
934 /* Any errors? */
935 if (r != OK) {
936 /* Don't retry if sector marked bad or too many errors. */
937 if (r == ERR_BAD_SECTOR || ++errors == max_errors) {
938 w_command = CMD_IDLE;
939 return(EIO);
940 }
941 }
942 }
943
944 w_command = CMD_IDLE;
945 return(OK);
946}
947
948/*===========================================================================*
949 * com_out *
950 *===========================================================================*/
951PRIVATE int com_out(cmd)
952struct command *cmd; /* Command block */
953{
954/* Output the command block to the winchester controller and return status */
955
956 struct wini *wn = w_wn;
957 unsigned base_cmd = wn->base_cmd;
958 unsigned base_ctl = wn->base_ctl;
959 pvb_pair_t outbyte[7]; /* vector for sys_voutb() */
960 int s; /* status for sys_(v)outb() */
961
962 if (w_wn->state & IGNORING) return ERR;
963
964 if (!w_waitfor(STATUS_BSY, 0)) {
965 printf("%s: controller not ready\n", w_name());
966 return(ERR);
967 }
968
969 /* Select drive. */
970 if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)
971 panic(w_name(),"Couldn't write register to select drive",s);
972
973 if (!w_waitfor(STATUS_BSY, 0)) {
974 printf("%s: com_out: drive not ready\n", w_name());
975 return(ERR);
976 }
977
978 /* Schedule a wakeup call, some controllers are flaky. This is done with
979 * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent
980 * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the
981 * controller was not able to execute the command. Leftover timeouts are
982 * simply ignored by the main loop.
983 */
984 sys_setalarm(wakeup_ticks, 0);
985
986 wn->w_status = STATUS_ADMBSY;
987 w_command = cmd->command;
988 pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
989 pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp);
990 pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count);
991 pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector);
992 pv_set(outbyte[4], base_cmd + REG_CYL_LO, cmd->cyl_lo);
993 pv_set(outbyte[5], base_cmd + REG_CYL_HI, cmd->cyl_hi);
994 pv_set(outbyte[6], base_cmd + REG_COMMAND, cmd->command);
995 if ((s=sys_voutb(outbyte,7)) != OK)
996 panic(w_name(),"Couldn't write registers with sys_voutb()",s);
997 return(OK);
998}
999
1000/*===========================================================================*
1001 * w_need_reset *
1002 *===========================================================================*/
1003PRIVATE void w_need_reset()
1004{
1005/* The controller needs to be reset. */
1006 struct wini *wn;
1007 int dr = 0;
1008
1009 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++, dr++) {
1010 if (wn->base_cmd == w_wn->base_cmd) {
1011 wn->state |= DEAF;
1012 wn->state &= ~INITIALIZED;
1013 }
1014 }
1015}
1016
1017/*===========================================================================*
1018 * w_do_close *
1019 *===========================================================================*/
1020PRIVATE int w_do_close(dp, m_ptr)
1021struct driver *dp;
1022message *m_ptr;
1023{
1024/* Device close: Release a device. */
1025 if (w_prepare(m_ptr->DEVICE) == NIL_DEV)
1026 return(ENXIO);
1027 w_wn->open_ct--;
1028#if ENABLE_ATAPI
1029 if (w_wn->open_ct == 0 && (w_wn->state & ATAPI)) atapi_close();
1030#endif
1031 return(OK);
1032}
1033
1034/*===========================================================================*
1035 * com_simple *
1036 *===========================================================================*/
1037PRIVATE int com_simple(cmd)
1038struct command *cmd; /* Command block */
1039{
1040/* A simple controller command, only one interrupt and no data-out phase. */
1041 int r;
1042
1043 if (w_wn->state & IGNORING) return ERR;
1044
1045 if ((r = com_out(cmd)) == OK) r = at_intr_wait();
1046 w_command = CMD_IDLE;
1047 return(r);
1048}
1049
1050/*===========================================================================*
1051 * w_timeout *
1052 *===========================================================================*/
1053PRIVATE void w_timeout(void)
1054{
1055 struct wini *wn = w_wn;
1056
1057 switch (w_command) {
1058 case CMD_IDLE:
1059 break; /* fine */
1060 case CMD_READ:
1061 case CMD_WRITE:
1062 /* Impossible, but not on PC's: The controller does not respond. */
1063
1064 /* Limiting multisector I/O seems to help. */
1065 if (wn->max_count > 8 * SECTOR_SIZE) {
1066 wn->max_count = 8 * SECTOR_SIZE;
1067 } else {
1068 wn->max_count = SECTOR_SIZE;
1069 }
1070 /*FALL THROUGH*/
1071 default:
1072 /* Some other command. */
1073 if (w_testing) wn->state |= IGNORING; /* Kick out this drive. */
1074 else if (!w_silent) printf("%s: timeout on command %02x\n", w_name(), w_command);
1075 w_need_reset();
1076 wn->w_status = 0;
1077 }
1078}
1079
1080/*===========================================================================*
1081 * w_reset *
1082 *===========================================================================*/
1083PRIVATE int w_reset()
1084{
1085/* Issue a reset to the controller. This is done after any catastrophe,
1086 * like the controller refusing to respond.
1087 */
1088 int s;
1089 struct wini *wn = w_wn;
1090
1091 /* Don't bother if this drive is forgotten. */
1092 if (w_wn->state & IGNORING) return ERR;
1093
1094 /* Wait for any internal drive recovery. */
1095 tickdelay(RECOVERY_TICKS);
1096
1097 /* Strobe reset bit */
1098 if ((s=sys_outb(wn->base_ctl + REG_CTL, CTL_RESET)) != OK)
1099 panic(w_name(),"Couldn't strobe reset bit",s);
1100 tickdelay(DELAY_TICKS);
1101 if ((s=sys_outb(wn->base_ctl + REG_CTL, 0)) != OK)
1102 panic(w_name(),"Couldn't strobe reset bit",s);
1103 tickdelay(DELAY_TICKS);
1104
1105 /* Wait for controller ready */
1106 if (!w_waitfor(STATUS_BSY, 0)) {
1107 printf("%s: reset failed, drive busy\n", w_name());
1108 return(ERR);
1109 }
1110
1111 /* The error register should be checked now, but some drives mess it up. */
1112
1113 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
1114 if (wn->base_cmd == w_wn->base_cmd) {
1115 wn->state &= ~DEAF;
1116 if (w_wn->irq_need_ack) {
1117 /* Make sure irq is actually enabled.. */
1118 sys_irqenable(&w_wn->irq_hook_id);
1119 }
1120 }
1121 }
1122
1123
1124 return(OK);
1125}
1126
1127/*===========================================================================*
1128 * w_intr_wait *
1129 *===========================================================================*/
1130PRIVATE void w_intr_wait()
1131{
1132/* Wait for a task completion interrupt. */
1133
1134 message m;
1135
1136 if (w_wn->irq != NO_IRQ) {
1137 /* Wait for an interrupt that sets w_status to "not busy". */
1138 while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {
1139 receive(ANY, &m); /* expect HARD_INT message */
1140 if (m.m_type == SYN_ALARM) { /* but check for timeout */
1141 w_timeout(); /* a.o. set w_status */
1142 } else if (m.m_type == HARD_INT) {
1143 sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status);
1144 ack_irqs(m.NOTIFY_ARG);
1145 } else {
1146 printf("AT_WINI got unexpected message %d from %d\n",
1147 m.m_type, m.m_source);
1148 }
1149 }
1150 } else {
1151 /* Interrupt not yet allocated; use polling. */
1152 (void) w_waitfor(STATUS_BSY, 0);
1153 }
1154}
1155
1156/*===========================================================================*
1157 * at_intr_wait *
1158 *===========================================================================*/
1159PRIVATE int at_intr_wait()
1160{
1161/* Wait for an interrupt, study the status bits and return error/success. */
1162 int r;
1163 int s,inbval; /* read value with sys_inb */
1164
1165 w_intr_wait();
1166 if ((w_wn->w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) {
1167 r = OK;
1168 } else {
1169 if ((s=sys_inb(w_wn->base_cmd + REG_ERROR, &inbval)) != OK)
1170 panic(w_name(),"Couldn't read register",s);
1171 if ((w_wn->w_status & STATUS_ERR) && (inbval & ERROR_BB)) {
1172 r = ERR_BAD_SECTOR; /* sector marked bad, retries won't help */
1173 } else {
1174 r = ERR; /* any other error */
1175 }
1176 }
1177 w_wn->w_status |= STATUS_ADMBSY; /* assume still busy with I/O */
1178 return(r);
1179}
1180
1181/*===========================================================================*
1182 * w_waitfor *
1183 *===========================================================================*/
1184PRIVATE int w_waitfor(mask, value)
1185int mask; /* status mask */
1186int value; /* required status */
1187{
1188/* Wait until controller is in the required state. Return zero on timeout.
1189 * An alarm that set a timeout flag is used. TIMEOUT is in micros, we need
1190 * ticks. Disabling the alarm is not needed, because a static flag is used
1191 * and a leftover timeout cannot do any harm.
1192 */
1193 clock_t t0, t1;
1194 int s;
1195 getuptime(&t0);
1196 do {
1197 if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status)) != OK)
1198 panic(w_name(),"Couldn't read register",s);
1199 if ((w_wn->w_status & mask) == value) {
1200 return 1;
1201 }
1202 } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );
1203 if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
1204
1205 w_need_reset(); /* controller gone deaf */
1206 return(0);
1207}
1208
1209/*===========================================================================*
1210 * w_geometry *
1211 *===========================================================================*/
1212PRIVATE void w_geometry(entry)
1213struct partition *entry;
1214{
1215 struct wini *wn = w_wn;
1216
1217 if (wn->state & ATAPI) { /* Make up some numbers. */
1218 entry->cylinders = div64u(wn->part[0].dv_size, SECTOR_SIZE) / (64*32);
1219 entry->heads = 64;
1220 entry->sectors = 32;
1221 } else { /* Return logical geometry. */
1222 entry->cylinders = wn->lcylinders;
1223 entry->heads = wn->lheads;
1224 entry->sectors = wn->lsectors;
1225 }
1226}
1227
1228#if ENABLE_ATAPI
1229/*===========================================================================*
1230 * atapi_open *
1231 *===========================================================================*/
1232PRIVATE int atapi_open()
1233{
1234/* Should load and lock the device and obtain its size. For now just set the
1235 * size of the device to something big. What is really needed is a generic
1236 * SCSI layer that does all this stuff for ATAPI and SCSI devices (kjb). (XXX)
1237 */
1238 w_wn->part[0].dv_size = mul64u(800L*1024, 1024);
1239 return(OK);
1240}
1241
1242/*===========================================================================*
1243 * atapi_close *
1244 *===========================================================================*/
1245PRIVATE void atapi_close()
1246{
1247/* Should unlock the device. For now do nothing. (XXX) */
1248}
1249
1250void sense_request(void)
1251{
1252 int r, i;
1253 static u8_t sense[100], packet[ATAPI_PACKETSIZE];
1254
1255 packet[0] = SCSI_SENSE;
1256 packet[1] = 0;
1257 packet[2] = 0;
1258 packet[3] = 0;
1259 packet[4] = SENSE_PACKETSIZE;
1260 packet[5] = 0;
1261 packet[7] = 0;
1262 packet[8] = 0;
1263 packet[9] = 0;
1264 packet[10] = 0;
1265 packet[11] = 0;
1266
1267 for(i = 0; i < SENSE_PACKETSIZE; i++) sense[i] = 0xff;
1268 r = atapi_sendpacket(packet, SENSE_PACKETSIZE);
1269 if (r != OK) { printf("request sense command failed\n"); return; }
1270 if (atapi_intr_wait() <= 0) { printf("WARNING: request response failed\n"); }
1271
1272 if (sys_insw(w_wn->base_cmd + REG_DATA, SELF, (void *) sense, SENSE_PACKETSIZE) != OK)
1273 printf("WARNING: sense reading failed\n");
1274
1275 printf("sense data:");
1276 for(i = 0; i < SENSE_PACKETSIZE; i++) printf(" %02x", sense[i]);
1277 printf("\n");
1278}
1279
1280/*===========================================================================*
1281 * atapi_transfer *
1282 *===========================================================================*/
1283PRIVATE int atapi_transfer(proc_nr, opcode, position, iov, nr_req)
1284int proc_nr; /* process doing the request */
1285int opcode; /* DEV_GATHER or DEV_SCATTER */
1286off_t position; /* offset on device to read or write */
1287iovec_t *iov; /* pointer to read or write request vector */
1288unsigned nr_req; /* length of request vector */
1289{
1290 struct wini *wn = w_wn;
1291 iovec_t *iop, *iov_end = iov + nr_req;
1292 int r, s, errors, fresh;
1293 u64_t pos;
1294 unsigned long block;
1295 unsigned long dv_size = cv64ul(w_dv->dv_size);
1296 unsigned nbytes, nblocks, count, before, chunk;
1297 static u8_t packet[ATAPI_PACKETSIZE];
1298
1299 errors = fresh = 0;
1300
1301 while (nr_req > 0 && !fresh) {
1302 /* The Minix block size is smaller than the CD block size, so we
1303 * may have to read extra before or after the good data.
1304 */
1305 pos = add64ul(w_dv->dv_base, position);
1306 block = div64u(pos, CD_SECTOR_SIZE);
1307 before = rem64u(pos, CD_SECTOR_SIZE);
1308
1309 /* How many bytes to transfer? */
1310 nbytes = count = 0;
1311 for (iop = iov; iop < iov_end; iop++) {
1312 nbytes += iop->iov_size;
1313 if ((before + nbytes) % CD_SECTOR_SIZE == 0) count = nbytes;
1314 }
1315
1316 /* Does one of the memory chunks end nicely on a CD sector multiple? */
1317 if (count != 0) nbytes = count;
1318
1319 /* Data comes in as words, so we have to enforce even byte counts. */
1320 if ((before | nbytes) & 1) return(EINVAL);
1321
1322 /* Which block on disk and how close to EOF? */
1323 if (position >= dv_size) return(OK); /* At EOF */
1324 if (position + nbytes > dv_size) nbytes = dv_size - position;
1325
1326 nblocks = (before + nbytes + CD_SECTOR_SIZE - 1) / CD_SECTOR_SIZE;
1327 if (ATAPI_DEBUG) {
1328 printf("block=%lu, before=%u, nbytes=%u, nblocks=%u\n",
1329 block, before, nbytes, nblocks);
1330 }
1331
1332 /* First check to see if a reinitialization is needed. */
1333 if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
1334
1335 /* Build an ATAPI command packet. */
1336 packet[0] = SCSI_READ10;
1337 packet[1] = 0;
1338 packet[2] = (block >> 24) & 0xFF;
1339 packet[3] = (block >> 16) & 0xFF;
1340 packet[4] = (block >> 8) & 0xFF;
1341 packet[5] = (block >> 0) & 0xFF;
1342 packet[7] = (nblocks >> 8) & 0xFF;
1343 packet[8] = (nblocks >> 0) & 0xFF;
1344 packet[9] = 0;
1345 packet[10] = 0;
1346 packet[11] = 0;
1347
1348 /* Tell the controller to execute the packet command. */
1349 r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE);
1350 if (r != OK) goto err;
1351
1352 /* Read chunks of data. */
1353 while ((r = atapi_intr_wait()) > 0) {
1354 count = r;
1355
1356 if (ATAPI_DEBUG) {
1357 printf("before=%u, nbytes=%u, count=%u\n",
1358 before, nbytes, count);
1359 }
1360
1361 while (before > 0 && count > 0) { /* Discard before. */
1362 chunk = before;
1363 if (chunk > count) chunk = count;
1364 if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
1365 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK)
1366 panic(w_name(),"Call to sys_insw() failed", s);
1367 before -= chunk;
1368 count -= chunk;
1369 }
1370
1371 while (nbytes > 0 && count > 0) { /* Requested data. */
1372 chunk = nbytes;
1373 if (chunk > count) chunk = count;
1374 if (chunk > iov->iov_size) chunk = iov->iov_size;
1375 if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, chunk)) != OK)
1376 panic(w_name(),"Call to sys_insw() failed", s);
1377 position += chunk;
1378 nbytes -= chunk;
1379 count -= chunk;
1380 iov->iov_addr += chunk;
1381 fresh = 0;
1382 if ((iov->iov_size -= chunk) == 0) {
1383 iov++;
1384 nr_req--;
1385 fresh = 1; /* new element is optional */
1386 }
1387 }
1388
1389 while (count > 0) { /* Excess data. */
1390 chunk = count;
1391 if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
1392 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK)
1393 panic(w_name(),"Call to sys_insw() failed", s);
1394 count -= chunk;
1395 }
1396 }
1397
1398 if (r < 0) {
1399 err: /* Don't retry if too many errors. */
1400 if (atapi_debug) sense_request();
1401 if (++errors == max_errors) {
1402 w_command = CMD_IDLE;
1403 if (atapi_debug) printf("giving up (%d)\n", errors);
1404 return(EIO);
1405 }
1406 if (atapi_debug) printf("retry (%d)\n", errors);
1407 }
1408 }
1409
1410 w_command = CMD_IDLE;
1411 return(OK);
1412}
1413
1414/*===========================================================================*
1415 * atapi_sendpacket *
1416 *===========================================================================*/
1417PRIVATE int atapi_sendpacket(packet, cnt)
1418u8_t *packet;
1419unsigned cnt;
1420{
1421/* Send an Atapi Packet Command */
1422 struct wini *wn = w_wn;
1423 pvb_pair_t outbyte[6]; /* vector for sys_voutb() */
1424 int s;
1425
1426 if (wn->state & IGNORING) return ERR;
1427
1428 /* Select Master/Slave drive */
1429 if ((s=sys_outb(wn->base_cmd + REG_DRIVE, wn->ldhpref)) != OK)
1430 panic(w_name(),"Couldn't select master/ slave drive",s);
1431
1432 if (!w_waitfor(STATUS_BSY | STATUS_DRQ, 0)) {
1433 printf("%s: atapi_sendpacket: drive not ready\n", w_name());
1434 return(ERR);
1435 }
1436
1437 /* Schedule a wakeup call, some controllers are flaky. This is done with
1438 * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent
1439 * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the
1440 * controller was not able to execute the command. Leftover timeouts are
1441 * simply ignored by the main loop.
1442 */
1443 sys_setalarm(wakeup_ticks, 0);
1444
1445#if _WORD_SIZE > 2
1446 if (cnt > 0xFFFE) cnt = 0xFFFE; /* Max data per interrupt. */
1447#endif
1448
1449 w_command = ATAPI_PACKETCMD;
1450 pv_set(outbyte[0], wn->base_cmd + REG_FEAT, 0);
1451 pv_set(outbyte[1], wn->base_cmd + REG_IRR, 0);
1452 pv_set(outbyte[2], wn->base_cmd + REG_SAMTAG, 0);
1453 pv_set(outbyte[3], wn->base_cmd + REG_CNT_LO, (cnt >> 0) & 0xFF);
1454 pv_set(outbyte[4], wn->base_cmd + REG_CNT_HI, (cnt >> 8) & 0xFF);
1455 pv_set(outbyte[5], wn->base_cmd + REG_COMMAND, w_command);
1456 if (atapi_debug) printf("cmd: %x ", w_command);
1457 if ((s=sys_voutb(outbyte,6)) != OK)
1458 panic(w_name(),"Couldn't write registers with sys_voutb()",s);
1459
1460 if (!w_waitfor(STATUS_BSY | STATUS_DRQ, STATUS_DRQ)) {
1461 printf("%s: timeout (BSY|DRQ -> DRQ)\n", w_name());
1462 return(ERR);
1463 }
1464 wn->w_status |= STATUS_ADMBSY; /* Command not at all done yet. */
1465
1466 /* Send the command packet to the device. */
1467 if ((s=sys_outsw(wn->base_cmd + REG_DATA, SELF, packet, ATAPI_PACKETSIZE)) != OK)
1468 panic(w_name(),"sys_outsw() failed", s);
1469
1470 {
1471 int p;
1472 if (atapi_debug) {
1473 printf("sent command:");
1474 for(p = 0; p < ATAPI_PACKETSIZE; p++) { printf(" %02x", packet[p]); }
1475 printf("\n");
1476 }
1477 }
1478 return(OK);
1479}
1480
1481
1482#endif /* ENABLE_ATAPI */
1483
1484/*===========================================================================*
1485 * w_other *
1486 *===========================================================================*/
1487PRIVATE int w_other(dr, m)
1488struct driver *dr;
1489message *m;
1490{
1491 int r, timeout, prev;
1492
1493 if (m->m_type != DEV_IOCTL ) {
1494 return EINVAL;
1495 }
1496
1497 if (m->REQUEST == DIOCTIMEOUT) {
1498 if ((r=sys_datacopy(m->PROC_NR, (vir_bytes)m->ADDRESS,
1499 SELF, (vir_bytes)&timeout, sizeof(timeout))) != OK)
1500 return r;
1501
1502 if (timeout == 0) {
1503 /* Restore defaults. */
1504 timeout_ticks = DEF_TIMEOUT_TICKS;
1505 max_errors = MAX_ERRORS;
1506 wakeup_ticks = WAKEUP;
1507 w_silent = 0;
1508 } else if (timeout < 0) {
1509 return EINVAL;
1510 } else {
1511 prev = wakeup_ticks;
1512
1513 if (!w_standard_timeouts) {
1514 /* Set (lower) timeout, lower error
1515 * tolerance and set silent mode.
1516 */
1517 wakeup_ticks = timeout;
1518 max_errors = 3;
1519 w_silent = 1;
1520
1521 if (timeout_ticks > timeout)
1522 timeout_ticks = timeout;
1523 }
1524
1525 if ((r=sys_datacopy(SELF, (vir_bytes)&prev,
1526 m->PROC_NR, (vir_bytes)m->ADDRESS, sizeof(prev))) != OK)
1527 return r;
1528 }
1529
1530 return OK;
1531 } else if (m->REQUEST == DIOCOPENCT) {
1532 int count;
1533 if (w_prepare(m->DEVICE) == NIL_DEV) return ENXIO;
1534 count = w_wn->open_ct;
1535 if ((r=sys_datacopy(SELF, (vir_bytes)&count,
1536 m->PROC_NR, (vir_bytes)m->ADDRESS, sizeof(count))) != OK)
1537 return r;
1538 return OK;
1539 }
1540 return EINVAL;
1541}
1542
1543/*===========================================================================*
1544 * w_hw_int *
1545 *===========================================================================*/
1546PRIVATE int w_hw_int(dr, m)
1547struct driver *dr;
1548message *m;
1549{
1550 /* Leftover interrupt(s) received; ack it/them. */
1551 ack_irqs(m->NOTIFY_ARG);
1552
1553 return OK;
1554}
1555
1556
1557/*===========================================================================*
1558 * ack_irqs *
1559 *===========================================================================*/
1560PRIVATE void ack_irqs(unsigned int irqs)
1561{
1562 unsigned int drive;
1563 for (drive = 0; drive < MAX_DRIVES && irqs; drive++) {
1564 if (!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack &&
1565 (wini[drive].irq_mask & irqs)) {
1566 if (sys_inb((wini[drive].base_cmd + REG_STATUS), &wini[drive].w_status) != OK)
1567 printf("couldn't ack irq on drive %d\n", drive);
1568 if (sys_irqenable(&wini[drive].irq_hook_id) != OK)
1569 printf("couldn't re-enable drive %d\n", drive);
1570 irqs &= ~wini[drive].irq_mask;
1571 }
1572 }
1573}
1574
1575
1576#define STSTR(a) if (status & STATUS_ ## a) { strcat(str, #a); strcat(str, " "); }
1577#define ERRSTR(a) if (e & ERROR_ ## a) { strcat(str, #a); strcat(str, " "); }
1578char *strstatus(int status)
1579{
1580 static char str[200];
1581 str[0] = '\0';
1582
1583 STSTR(BSY);
1584 STSTR(DRDY);
1585 STSTR(DMADF);
1586 STSTR(SRVCDSC);
1587 STSTR(DRQ);
1588 STSTR(CORR);
1589 STSTR(CHECK);
1590 return str;
1591}
1592
1593char *strerr(int e)
1594{
1595 static char str[200];
1596 str[0] = '\0';
1597
1598 ERRSTR(BB);
1599 ERRSTR(ECC);
1600 ERRSTR(ID);
1601 ERRSTR(AC);
1602 ERRSTR(TK);
1603 ERRSTR(DM);
1604
1605 return str;
1606}
1607
1608#if ENABLE_ATAPI
1609
1610/*===========================================================================*
1611 * atapi_intr_wait *
1612 *===========================================================================*/
1613PRIVATE int atapi_intr_wait()
1614{
1615/* Wait for an interrupt and study the results. Returns a number of bytes
1616 * that need to be transferred, or an error code.
1617 */
1618 struct wini *wn = w_wn;
1619 pvb_pair_t inbyte[4]; /* vector for sys_vinb() */
1620 int s; /* status for sys_vinb() */
1621 int e;
1622 int len;
1623 int irr;
1624 int r;
1625 int phase;
1626
1627 w_intr_wait();
1628
1629 /* Request series of device I/O. */
1630 inbyte[0].port = wn->base_cmd + REG_ERROR;
1631 inbyte[1].port = wn->base_cmd + REG_CNT_LO;
1632 inbyte[2].port = wn->base_cmd + REG_CNT_HI;
1633 inbyte[3].port = wn->base_cmd + REG_IRR;
1634 if ((s=sys_vinb(inbyte, 4)) != OK)
1635 panic(w_name(),"ATAPI failed sys_vinb()", s);
1636 e = inbyte[0].value;
1637 len = inbyte[1].value;
1638 len |= inbyte[2].value << 8;
1639 irr = inbyte[3].value;
1640
1641#if ATAPI_DEBUG
1642 printf("wn %p S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn, wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);
1643#endif
1644 if (wn->w_status & (STATUS_BSY | STATUS_CHECK)) {
1645 if (atapi_debug) {
1646 printf("atapi fail: S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);
1647 }
1648 return ERR;
1649 }
1650
1651 phase = (wn->w_status & STATUS_DRQ) | (irr & (IRR_COD | IRR_IO));
1652
1653 switch (phase) {
1654 case IRR_COD | IRR_IO:
1655 if (ATAPI_DEBUG) printf("ACD: Phase Command Complete\n");
1656 r = OK;
1657 break;
1658 case 0:
1659 if (ATAPI_DEBUG) printf("ACD: Phase Command Aborted\n");
1660 r = ERR;
1661 break;
1662 case STATUS_DRQ | IRR_COD:
1663 if (ATAPI_DEBUG) printf("ACD: Phase Command Out\n");
1664 r = ERR;
1665 break;
1666 case STATUS_DRQ:
1667 if (ATAPI_DEBUG) printf("ACD: Phase Data Out %d\n", len);
1668 r = len;
1669 break;
1670 case STATUS_DRQ | IRR_IO:
1671 if (ATAPI_DEBUG) printf("ACD: Phase Data In %d\n", len);
1672 r = len;
1673 break;
1674 default:
1675 if (ATAPI_DEBUG) printf("ACD: Phase Unknown\n");
1676 r = ERR;
1677 break;
1678 }
1679
1680#if 0
1681 /* retry if the media changed */
1682 XXX while (phase == (IRR_IO | IRR_COD) && (wn->w_status & STATUS_CHECK)
1683 && (e & ERROR_SENSE) == SENSE_UATTN && --try > 0);
1684#endif
1685
1686 wn->w_status |= STATUS_ADMBSY; /* Assume not done yet. */
1687 return(r);
1688}
1689#endif /* ENABLE_ATAPI */
Note: See TracBrowser for help on using the repository browser.