Get the build system working again with the new boot/ dir structure
[newos.git] / kernel / addons / dev / arch / i386 / ide2 / ata_ide_drive.c
blob358657b565083b3cb55aeb836f7db21ef039d6b1
1 #include "ide_bus.h"
2 #include "ata_ide_drive.h"
4 #include <kernel/dev/arch/i386/ide/ide_bus.h>
5 #include <kernel/heap.h>
6 #include <kernel/debug.h>
7 #include <kernel/lock.h>
8 #define CB_DC_HD15 0x08 // bit should always be set to one
9 #define CB_DC_NIEN 0x02 // disable interrupts
11 #define CB_DH_DEV0 0xa0 // select device 0
12 #define CB_DH_DEV1 0xb0 // select device 1
14 #define DH_DRV1 0x1
15 #define DH_LBA 0x400
17 // Most mandtory and optional ATA commands (from ATA-3),
19 #define CMD_CFA_ERASE_SECTORS 0xC0
20 #define CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
21 #define CMD_CFA_TRANSLATE_SECTOR 0x87
22 #define CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
23 #define CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
24 #define CMD_CHECK_POWER_MODE1 0xE5
25 #define CMD_CHECK_POWER_MODE2 0x98
26 #define CMD_DEVICE_RESET 0x08
27 #define CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
28 #define CMD_FLUSH_CACHE 0xE7
29 #define CMD_FORMAT_TRACK 0x50
30 #define CMD_IDENTIFY_DEVICE 0xEC
31 #define CMD_IDENTIFY_DEVICE_PACKET 0xA1
32 #define CMD_IDENTIFY_PACKET_DEVICE 0xA1
33 #define CMD_IDLE1 0xE3
34 #define CMD_IDLE2 0x97
35 #define CMD_IDLE_IMMEDIATE1 0xE1
36 #define CMD_IDLE_IMMEDIATE2 0x95
37 #define CMD_INITIALIZE_DRIVE_PARAMETERS 0x91
38 #define CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
39 #define CMD_NOP 0x00
40 #define CMD_PACKET 0xA0
41 #define CMD_READ_BUFFER 0xE4
42 #define CMD_READ_DMA 0xC8
43 #define CMD_READ_DMA_QUEUED 0xC7
44 #define CMD_READ_MULTIPLE 0xC4
45 #define CMD_READ_SECTORS 0x20
46 #define CMD_READ_VERIFY_SECTORS 0x40
47 #define CMD_RECALIBRATE 0x10
48 #define CMD_SEEK 0x70
49 #define CMD_SET_FEATURES 0xEF
50 #define CMD_SET_MULTIPLE_MODE 0xC6
51 #define CMD_SLEEP1 0xE6
52 #define CMD_SLEEP2 0x99
53 #define CMD_STANDBY1 0xE2
54 #define CMD_STANDBY2 0x96
55 #define CMD_STANDBY_IMMEDIATE1 0xE0
56 #define CMD_STANDBY_IMMEDIATE2 0x94
57 #define CMD_WRITE_BUFFER 0xE8
58 #define CMD_WRITE_DMA 0xCA
59 #define CMD_WRITE_DMA_QUEUED 0xCC
60 #define CMD_WRITE_MULTIPLE 0xC5
61 #define CMD_WRITE_SECTORS 0x30
62 #define CMD_WRITE_VERIFY 0x3C
66 #define CB_STAT_BSY 0x80 // busy
67 #define CB_STAT_RDY 0x40 // ready
68 #define CB_STAT_DF 0x20 // device fault
69 #define CB_STAT_WFT 0x20 // write fault (old name)
70 #define CB_STAT_SKC 0x10 // seek complete
71 #define CB_STAT_SERV 0x10 // service
72 #define CB_STAT_DRQ 0x08 // data request
73 #define CB_STAT_CORR 0x04 // corrected
74 #define CB_STAT_IDX 0x02 // index
75 #define CB_STAT_ERR 0x01 // error (ATA)
76 #define CB_STAT_CHK 0x01 // check (ATAPI)
78 #define NO_ERR 0
79 #define ERR_EXPIRED_TIME_OUT -1
80 #define ERR_DISK_BUSY -2
81 #define ERR_HARDWARE_ERROR -3
82 #define ERR_DRQ_NOT_SET -4
83 #define ERR_TRANSMIT_BUFFER_NOT_EMPTY -5
84 #define ERR_DEVICE_FAULT -6
86 #define DRIVE_SUPPORT_LBA 0x0200
88 #define IDE_TRACE 1
90 #if IDE_TRACE
91 #define TRACE(x) dprintf x
92 #else
93 #define TRACE(x)
94 #endif
96 #define STATUS_WAITING_INTR 1
97 #define STATUS_IDLE 2
98 typedef struct s_ata_command
100 int cmd;
101 int fr;
102 int sc;
103 int cyl;
104 int head;
105 int sect;
106 uint8 *output;
107 int numSect;
108 int multiCnt;
109 bool read;
110 bool useInterrupt;
111 }ata_command;
113 typedef struct
115 ide_bus *attached_bus;
116 void *attached_bus_cookie;
117 int position;
118 bool lba_supported;
119 long sector_count;
120 uint16 bytes_per_sector;
121 ide_drive_info device_info;
122 int status;
123 ata_command *active_command;
124 mutex interrupt_mutex;
125 }ata_drive_cookie;
126 static void ide_reg_poll(ide_bus *bus, void *b_cookie)
128 uint8 status;
129 while(1)
131 status = bus->get_alt_status(b_cookie); // poll for not busy
132 if ( ( status & CB_STAT_BSY ) == 0 )
133 break;
136 static int convert_error(int error)
138 if(error & CB_STAT_BSY)
139 return ERR_DISK_BUSY;
140 if(error & CB_STAT_DF)
141 return ERR_DEVICE_FAULT;
142 if(error & CB_STAT_ERR)
143 return ERR_HARDWARE_ERROR;
145 return 0;
149 static void signal_interrupt(void *b_cookie,void *drive_cookie)
151 ata_drive_cookie *cookie = drive_cookie;
152 TRACE(("in signal interrupt status is %d\n",cookie->status));
153 if(cookie->status == STATUS_WAITING_INTR)
155 TRACE(("unlock mutex\n"));
156 mutex_unlock(&cookie->interrupt_mutex);
159 int execute_command( ide_bus *bus, void *b_cookie,ata_drive_cookie *drive_cookie,ata_command *command)
161 unsigned char devHead;
162 unsigned char devCtrl;
163 unsigned char cylLow;
164 unsigned char cylHigh;
165 unsigned char status;
166 unsigned int wordCnt;
167 int i;
168 uint16 *buffer = (uint16*)command->output;
169 int error_code;
170 if(command->useInterrupt==true)
171 devCtrl = CB_DC_HD15;
172 else
173 devCtrl = CB_DC_HD15 | CB_DC_NIEN;
174 devHead = drive_cookie->position ? CB_DH_DEV1 : CB_DH_DEV0;
175 devHead = devHead | ( command->head & 0x4f );
176 cylLow = command->cyl & 0x00ff;
177 cylHigh = ( command->cyl & 0xff00 ) >> 8;
178 // these commands transfer only 1 sector
179 if (( command->cmd == CMD_IDENTIFY_DEVICE )|| ( command->cmd == CMD_IDENTIFY_DEVICE_PACKET )|| ( command->cmd == CMD_READ_BUFFER )|| ( command->cmd == CMD_WRITE_BUFFER))
180 command->numSect = 1;
181 // only Read Multiple uses multiCnt
182 if ( (command->cmd != CMD_READ_MULTIPLE ) && ( command->cmd != CMD_WRITE_MULTIPLE ) && ( command->cmd != CMD_CFA_WRITE_MULTIPLE_WO_ERASE ))
183 command->multiCnt = 1;
185 if(command->useInterrupt)
187 drive_cookie->active_command = command;
188 drive_cookie->status = STATUS_WAITING_INTR;
190 if ( bus->select_drive( b_cookie,drive_cookie->position) )
192 return ERR_EXPIRED_TIME_OUT;
194 bus->write_register(b_cookie, CB_DC, devCtrl );
195 bus->write_register(b_cookie, CB_FR, command->fr );
196 bus->write_register(b_cookie, CB_SC, command->sc );
197 bus->write_register(b_cookie, CB_SN, command->sect );
198 bus->write_register(b_cookie, CB_CL, cylLow );
199 bus->write_register(b_cookie, CB_CH, cylHigh );
200 bus->write_register(b_cookie, CB_DH, devHead );
202 bus->write_register(b_cookie, CB_CMD, command->cmd );
204 if(command->useInterrupt)
206 TRACE(("locking interrupt mutex\n"));
207 mutex_lock(&drive_cookie->interrupt_mutex);
208 TRACE(("entering wait loop\n"));
210 else
212 bus->delay_on_bus(b_cookie);
214 while ( 1 )
216 if(command->read)
218 if(command->useInterrupt)
220 mutex_lock(&drive_cookie->interrupt_mutex);
221 mutex_unlock(&drive_cookie->interrupt_mutex);
223 else
224 ide_reg_poll(bus,b_cookie);
226 status = bus->get_alt_status(b_cookie);
227 if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) == CB_STAT_DRQ )
229 wordCnt = command->multiCnt ? command->multiCnt : 1;
230 if ( wordCnt > command->numSect )
231 wordCnt = command->numSect;
232 wordCnt = wordCnt * 256;
233 bus->transfer_buffer( b_cookie,CB_DATA, buffer, wordCnt ,command->read);
234 bus->delay_on_bus(b_cookie);
235 command->numSect = command->numSect - ( command->multiCnt ? command->multiCnt : 1 );
236 buffer+=wordCnt;
238 if(!command->read)
240 if(command->useInterrupt)
242 mutex_lock(&drive_cookie->interrupt_mutex);
243 mutex_unlock(&drive_cookie->interrupt_mutex);
245 else
246 ide_reg_poll(bus,b_cookie);
247 status = bus->get_alt_status(b_cookie);
249 error_code = convert_error(status);
250 if(error_code!=0)
251 return error_code;
252 if ( ( status & CB_STAT_DRQ ) == 0 )
254 return ERR_DRQ_NOT_SET;
256 if ( command->numSect < 1 )
258 status = bus->get_alt_status(b_cookie);
259 error_code = convert_error(status);
260 if(error_code!=0)
261 return error_code;
262 if( status & CB_STAT_DRQ)
264 return ERR_TRANSMIT_BUFFER_NOT_EMPTY;
266 break; // go to READ_DONE
269 drive_cookie->status = STATUS_IDLE;
270 return NO_ERR;
272 int execute_command_dma( ide_bus *bus, void *b_cookie,ata_drive_cookie *drive_cookie, ata_command *command)
275 unsigned char devHead;
276 unsigned char devCtrl;
277 unsigned char cylLow;
278 unsigned char cylHigh;
279 unsigned char status;
280 int ns;
281 unsigned long lw1, lw2;
282 int doTwo;
284 // setup register values
286 dprintf("entering execute_command_dma %X %X %X %X %X\n",bus,b_cookie,drive_cookie,command,command->output);
287 devCtrl = 0;
288 devHead = drive_cookie->position ? CB_DH_DEV1 : CB_DH_DEV0;
289 devHead = devHead | ( command->head & 0x4f );
290 cylLow = command->cyl & 0x00ff;
291 cylHigh = ( command->cyl & 0xff00 ) >> 8;
293 // Quit now if the command is incorrect.
295 if ( ( command->cmd != CMD_READ_DMA) && ( command->cmd != CMD_WRITE_DMA) )
297 return -1;
300 // set up the dma transfer(s)
302 ns = command->sc;
303 if ( ! ns )
304 ns = 256;
305 drive_cookie->active_command = command;
306 doTwo = bus->setup_dma(b_cookie,command->cmd == CMD_WRITE_DMA, ns * 512L, command->output);
308 if ( bus->select_drive( b_cookie,drive_cookie->position) )
310 return ERR_EXPIRED_TIME_OUT;
312 // Set up all the registers except the command register.
313 bus->write_register(b_cookie, CB_DC, devCtrl );
314 bus->write_register(b_cookie, CB_FR, command->fr );
315 bus->write_register(b_cookie, CB_SC, command->sc );
316 bus->write_register(b_cookie, CB_SN, command->sect );
317 bus->write_register(b_cookie, CB_CL, cylLow );
318 bus->write_register(b_cookie, CB_CH, cylHigh );
319 bus->write_register(b_cookie, CB_DH, devHead );
321 bus->write_register(b_cookie, CB_CMD, command->cmd );
322 drive_cookie->status = STATUS_WAITING_INTR;
323 bus->delay_on_bus(b_cookie);
324 bus->start_dma( b_cookie);
325 dprintf("first lock\n");
326 mutex_lock(&drive_cookie->interrupt_mutex);
327 dprintf("second lock\n");
329 mutex_lock(&drive_cookie->interrupt_mutex);
330 mutex_unlock(&drive_cookie->interrupt_mutex);
331 return bus->finish_dma(b_cookie);
333 static void ide_string_conv (char *str, int len)
335 unsigned int i;
336 int j;
337 for (i = 0; i < len / sizeof (unsigned short); i++)
339 char c = str[i*2+1];
340 str[i*2+1] = str[i*2];
341 str[i*2] = c;
344 str[len - 1] = 0;
345 for (j = len - 1; j >= 0 && str[j] == ' '; j--)
346 str[j] = 0;
349 int ide_identify_device (ide_bus *bus, void *b_cookie,ata_drive_cookie *drive_cookie,int bus_pos)
351 int ret;
352 uint8 *buffer;
353 ata_command command;
355 buffer = (uint8*)&drive_cookie->device_info;
356 TRACE(("executing command\n"));
357 command.cmd = CMD_IDENTIFY_DEVICE;
358 command.fr = 1;
359 command.sc = 0;
360 command.cyl = 0;
361 command.head = 0;
362 command.sect = 0;
363 command.output = buffer;
364 command.numSect = 1;
365 command.multiCnt = 0;
366 command.read = true;
367 command.useInterrupt = false;
368 ret = execute_command( bus,b_cookie,drive_cookie,&command);
369 TRACE(("executing command %d\n",ret));
370 if(ret<0)
371 return -1;
372 ide_string_conv(drive_cookie->device_info.model,40);
373 drive_cookie->sector_count = drive_cookie->device_info.cyls*drive_cookie->device_info.heads*drive_cookie->device_info.sectors;
374 drive_cookie->bytes_per_sector = 512;
375 drive_cookie->lba_supported = drive_cookie->device_info.capabilities & DRIVE_SUPPORT_LBA;
377 TRACE( ("ide: disk at bus %d, device %d %s\n", bus_pos, drive_cookie->position,drive_cookie->device_info.model));
378 TRACE(("ide/%d/%d: %dMB; %d cyl, %d head, %d sec, %d bytes/sec (LBA=%d)\n",bus_pos, drive_cookie->position,
379 drive_cookie->sector_count * drive_cookie->bytes_per_sector / 1024,
380 drive_cookie->device_info.cyls,
381 drive_cookie->device_info.heads,
382 drive_cookie->device_info.sectors,
383 drive_cookie->bytes_per_sector,
384 drive_cookie->lba_supported
386 return 0;
388 static void *init_drive(ide_bus *bus,void *b_cookie,int channel,int drive)
390 uint8 sc,sn,ch,cl,st;
391 unsigned char devCtrl = CB_DC_HD15 | CB_DC_NIEN ;
392 void *ret = NULL;
394 bus->write_register(b_cookie,CB_DC,devCtrl);
395 bus->select_drive(b_cookie,drive);
396 bus->delay_on_bus(b_cookie);
398 bus->write_register( b_cookie,CB_SC, 0x55 );
399 bus->write_register( b_cookie,CB_SN, 0xaa );
400 bus->write_register( b_cookie,CB_SC, 0xaa );
401 bus->write_register( b_cookie,CB_SN, 0x55 );
402 bus->write_register( b_cookie,CB_SC, 0x55 );
403 bus->write_register( b_cookie,CB_SN, 0xaa );
404 sc = bus->read_register( b_cookie,CB_SC );
405 sn = bus->read_register( b_cookie,CB_SN );
406 if(sc!=0x55 && sn!=0xaa)
408 return NULL;
410 bus->select_drive(b_cookie,drive);
411 bus->delay_on_bus(b_cookie);
412 bus->reset_bus( b_cookie,drive);
413 bus->select_drive(b_cookie,drive);
414 bus->delay_on_bus(b_cookie);
415 sc = bus->read_register( b_cookie,CB_SC );
416 sn = bus->read_register( b_cookie,CB_SN );
417 if ( ( sc == 0x01 ) && ( sn == 0x01 ) )
419 ret = NULL;
420 cl = bus->read_register( b_cookie,CB_CL );
421 ch = bus->read_register( b_cookie,CB_CH );
422 st = bus->read_register( b_cookie,CB_STAT );
423 if ( ( cl == 0x14 ) && ( ch == 0xeb ) )
424 ret = NULL;
425 else
426 if ( ( cl == 0x00 ) && ( ch == 0x00 ) && ( st != 0x00 ) )
428 ata_drive_cookie *cookie = kmalloc(sizeof(ata_drive_cookie));
429 cookie->attached_bus = bus;
430 cookie->attached_bus_cookie = b_cookie;
431 cookie->position = drive;
432 mutex_init(&cookie->interrupt_mutex,"test");
433 if(ide_identify_device(bus,b_cookie,cookie,channel)==0)
434 ret = cookie;
435 else
436 ret = NULL;
439 return ret;
441 void ide_btochs(uint32 block, ata_drive_cookie *dev, int *cylinder, int *head, int *sect)
443 uint32 sav_block = block;
444 *sect = (block % dev->device_info.sectors) + 1;
445 block /= dev->device_info.sectors;
446 *head = (block % dev->device_info.heads) | (dev->position ? DH_DRV1 : 0);
447 block /= dev->device_info.heads;
448 *cylinder = block & 0xFFFF;
449 TRACE(("ide_btochs: block %d -> cyl %d head %d sect %d\n", sav_block, *cylinder, *head, *sect));
451 void ide_btolba(uint32 block, ata_drive_cookie *dev, int *cylinder,int *head, int *sect)
453 uint32 sav_block = block;
454 *sect = block & 0xFF;
455 *cylinder = (block >> 8) & 0xFFFF;
456 *head = ((block >> 24) & 0xF) | ( dev->position ? DH_DRV1: 0) | DH_LBA;
457 TRACE(("ide_btolba: block %d -> cyl %d head %d sect %d\n", sav_block, *cylinder, *head, *sect));
459 static int read_block(void *b_cookie,void *d_cookie,long block,void *buffer,size_t size)
461 ata_drive_cookie *drive_cookie = d_cookie;
462 ide_bus *bus = drive_cookie->attached_bus;
463 int cyl, head, sect;
464 ata_command command;
465 TRACE(("in read_blocks %x\n",block));
466 if(drive_cookie->lba_supported==1)
467 ide_btolba(block, drive_cookie, &cyl, &head, &sect);
468 else
469 ide_btochs(block, drive_cookie, &cyl, &head, &sect);
471 TRACE(("about to read from %d %d %d\n",cyl,head,sect));
472 command.fr = 0;
473 command.sc = size;
474 command.cyl = cyl;
475 command.head = head;
476 command.sect = sect;
477 command.output = buffer;
478 command.numSect = size;
479 command.multiCnt = 2;
480 command.read = true;
481 command.useInterrupt = true;
482 if(drive_cookie->attached_bus->support_dma(b_cookie)==true)
484 TRACE(("Will use DMA to transfer data\n"));
485 command.cmd = CMD_READ_DMA;
486 return execute_command_dma( bus,b_cookie,drive_cookie,&command);
488 else
490 TRACE(("Will use PIO to transfer data\n"));
491 command.cmd = CMD_READ_SECTORS;
492 return execute_command( bus,b_cookie,drive_cookie,&command);
495 static int write_block(void *b_cookie,void *d_cookie,long block,const void *buffer,size_t size)
497 ata_drive_cookie *drive_cookie = d_cookie;
498 ide_bus *bus = drive_cookie->attached_bus;
499 int cyl, head, sect;
500 ata_command command;
501 if(drive_cookie->lba_supported==1)
502 ide_btolba(block, drive_cookie, &cyl, &head, &sect);
503 else
504 ide_btochs(block, drive_cookie, &cyl, &head, &sect);
505 command.fr = 0;
506 command.sc = size;
507 command.cyl = cyl;
508 command.head = head;
509 command.sect = sect;
510 command.output = buffer;
511 command.numSect = size;
512 command.multiCnt = 2;
513 command.read = false;
514 command.useInterrupt = true;
516 if(drive_cookie->attached_bus->support_dma(b_cookie)==true)
518 command.cmd = CMD_WRITE_DMA;
519 return execute_command_dma( bus,b_cookie,drive_cookie,&command);
521 else
523 command.cmd = CMD_WRITE_SECTORS;
524 return execute_command( bus,b_cookie,drive_cookie,&command);
528 static uint16 get_bytes_per_sector(void *d_cookie)
530 ata_drive_cookie *cookie = d_cookie;
531 return cookie->bytes_per_sector;
533 static int ioctl(void *b_cookie,void *d_cookie,int command,void *buffer,size_t size)
535 ata_drive_cookie *cookie = d_cookie;
536 int retCode;
537 switch(command)
539 case 10000:
541 /*if(size!=sizeof(device_information))
543 retCode = -1;
545 else
547 device_information *ret = (device_information*)buffer;
548 ret->bytes_per_sector = cookie->bytes_per_sector;
549 ret->sectors = cookie->sector_count;
550 ret->heads = cookie->device_info.heads;
551 ret->cylinders = cookie->device_info.cyls;
552 retCode = 0;
554 break;
556 default:
558 retCode = -1;
561 return retCode;
564 ide_drive ata_ide_drive =
566 "ATA_DRIVE",
567 &init_drive,
568 &read_block,
569 &write_block,
570 &get_bytes_per_sector,
571 &ioctl,
572 &signal_interrupt,
573 NULL