source: rtems/c/src/lib/libbsp/i386/pc386/ide/ide.c @ c16e54a

5
Last change on this file since c16e54a was 1503c1c3, checked in by Chris Johns <chrisj@…>, on 05/23/16 at 05:24:34

i386/pc386: Fix printk formatting warnings.

  • Property mode set to 100644
File size: 23.9 KB
Line 
1/*===============================================================*\
2| Project: RTEMS PC386 IDE harddisc driver                        |
3+-----------------------------------------------------------------+
4| File: ide.c                                                     |
5+-----------------------------------------------------------------+
6|                    Copyright (c) 2003 IMD                       |
7|      Ingenieurbuero fuer Microcomputertechnik Th. Doerfler      |
8|               <Thomas.Doerfler@imd-systems.de>                  |
9|                       all rights reserved                       |
10+-----------------------------------------------------------------+
11| this file contains the BSP layer for IDE access below the       |
12| libchip IDE harddisc driver                                     |
13| based on a board specific driver from                           |
14| Eugeny S. Mints, Oktet                                          |
15|                                                                 |
16|  The license and distribution terms for this file may be        |
17|  found in the file LICENSE in this distribution or at           |
18|  http://www.rtems.org/license/LICENSE.                     |
19|                                                                 |
20+-----------------------------------------------------------------+
21|   date                      history                        ID   |
22| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
23| 01.14.03  creation                                         doe  |
24\*===============================================================*/
25
26#include <inttypes.h>
27
28#include <rtems.h>
29
30#include <bsp.h>
31#include <libchip/ide_ctrl.h>
32#include <libchip/ide_ctrl_cfg.h>
33#include <libchip/ide_ctrl_io.h>
34
35#define ATA_SECTOR_SIZE (512)
36
37/*
38 * Use during initialisation.
39 */
40extern void Wait_X_ms(unsigned int msecs);
41
42bool pc386_ide_show;
43uint32_t pc386_ide_timeout;
44
45#define PC386_IDE_DEBUG_OUT 0
46
47#if PC386_IDE_DEBUG_OUT
48bool pc386_ide_trace;
49#define pc386_ide_printk if (pc386_ide_trace) printk
50#endif
51
52#define PC386_IDE_PROBE_TIMEOUT    (500)
53#define PC386_IDE_PRESTART_TIMEOUT (1000)
54#define PC386_IDE_TASKING_TIMEOUT  (2000)
55
56/*
57 * Prestart sleep using a calibrated timing loop.
58 */
59static void pc386_ide_prestart_sleep (void)
60{
61  Wait_X_ms (10);
62}
63
64/*
65 * Once tasking has started we use a task sleep.
66 */
67static void pc386_ide_tasking_sleep (void)
68{
69  rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (10000) ?
70                         RTEMS_MICROSECONDS_TO_TICKS (10000) : 1);
71}
72
73typedef void (*pc386_ide_sleeper)(void);
74
75static void pc386_ide_sleep (pc386_ide_sleeper sleeper)
76{
77  sleeper ();
78}
79
80static void wait(volatile uint32_t loops)
81{
82  while (loops)
83    loops--;
84}
85
86static bool pc386_ide_status_busy (uint32_t          port,
87                                   volatile uint32_t timeout,
88                                   uint8_t*          status_val,
89                                   pc386_ide_sleeper sleeper)
90{
91  volatile uint8_t status;
92  int              polls;
93
94  do
95  {
96    polls = 500;
97    while (polls)
98    {
99      inport_byte (port + IDE_REGISTER_STATUS, status);
100      if ((status & IDE_REGISTER_STATUS_BSY) == 0)
101      {
102        *status_val = status;
103        return true;
104      }
105      polls--;
106    }
107
108    if (timeout)
109    {
110      timeout--;
111      pc386_ide_sleep (sleeper);
112    }
113  }
114  while (timeout);
115
116  *status_val = status;
117  return false;
118}
119
120static bool pc386_ide_status_data_ready (uint32_t          port,
121                                         volatile uint32_t timeout,
122                                         uint8_t*          status_val,
123                                         pc386_ide_sleeper sleeper)
124{
125  volatile uint8_t status;
126  int              polls;
127
128  do
129  {
130    polls = 1000;
131    while (polls)
132    {
133      inport_byte (port + IDE_REGISTER_STATUS, status);
134
135      if (((status & IDE_REGISTER_STATUS_BSY) == 0) &&
136          (status & IDE_REGISTER_STATUS_DRQ))
137      {
138        *status_val = status;
139        return true;
140      }
141
142      polls--;
143    }
144
145    if (timeout)
146    {
147      timeout--;
148      pc386_ide_sleep (sleeper);
149    }
150  }
151  while (timeout);
152
153  *status_val = status;
154  return false;
155}
156
157/*
158 * support functions for IDE harddisk IF
159 */
160/*=========================================================================*\
161| Function:                                                                 |
162\*-------------------------------------------------------------------------*/
163static bool pc386_ide_probe
164(
165/*-------------------------------------------------------------------------*\
166| Purpose:                                                                  |
167|  This function should probe, whether a IDE disk is available              |
168+---------------------------------------------------------------------------+
169| Input Parameters:                                                         |
170\*-------------------------------------------------------------------------*/
171 int minor
172 )
173/*-------------------------------------------------------------------------*\
174| Return Value:                                                             |
175|    true, when flash disk available                                        |
176\*=========================================================================*/
177{
178  bool ide_card_plugged = true; /* assume: we have a disk here */
179
180  return ide_card_plugged;
181}
182
183/*=========================================================================*\
184| Function:                                                                 |
185\*-------------------------------------------------------------------------*/
186static void pc386_ide_initialize
187(
188/*-------------------------------------------------------------------------*\
189  | Purpose:                                                                  |
190  |  initialize IDE access                                                    |
191  +---------------------------------------------------------------------------+
192  | Input Parameters:                                                         |
193  \*-------------------------------------------------------------------------*/
194  int  minor                              /* controller minor number       */
195 )
196/*-------------------------------------------------------------------------*\
197  | Return Value:                                                             |
198  |    <none>                                                                 |
199  \*=========================================================================*/
200{
201  uint32_t port = IDE_Controller_Table[minor].port1;
202  uint8_t  dev = 0;
203
204  if (pc386_ide_show)
205    printk("IDE%d: port base: %04" PRIu32 "\n", minor, port);
206
207  outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
208               (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
209  wait(10000);
210  outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
211               IDE_REGISTER_DEVICE_CONTROL_SRST | IDE_REGISTER_DEVICE_CONTROL_nIEN);
212  wait(10000);
213  outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
214               IDE_REGISTER_DEVICE_CONTROL_nIEN);
215  wait(10000);
216
217  for (dev = 0; dev < 2; dev++)
218  {
219    uint16_t    capabilities = 0;
220    uint32_t    byte;
221    uint8_t     status;
222    uint8_t     error;
223    uint8_t     cyllsb;
224    uint8_t     cylmsb;
225    const char* label = dev ? " slave" : "master";
226    int         max_multiple_sectors = 0;
227    int         cur_multiple_sectors = 0;
228    uint32_t    cylinders = 0;
229    uint32_t    heads = 0;
230    uint32_t    sectors = 0;
231    uint32_t    lba_sectors = 0;
232    char        model_number[41];
233    char*       p = &model_number[0];
234    bool        data_ready;
235
236    (void) cur_multiple_sectors; /* avoid set but not used warning */
237
238    memset(model_number, 0, sizeof(model_number));
239
240    outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
241                 (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | 0xE0);
242    /*
243      outport_byte(port+IDE_REGISTER_SECTOR_NUMBER,
244      (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS) | IDE_REGISTER_LBA3_L);
245    */
246
247    outport_byte(port+IDE_REGISTER_COMMAND, 0x00);
248
249    if (!pc386_ide_status_busy (port, PC386_IDE_PROBE_TIMEOUT,
250                                &status, pc386_ide_prestart_sleep))
251      continue;
252
253    inport_byte(port+IDE_REGISTER_STATUS,        status);
254    inport_byte(port+IDE_REGISTER_ERROR,         error);
255    inport_byte(port+IDE_REGISTER_CYLINDER_LOW,  cyllsb);
256    inport_byte(port+IDE_REGISTER_CYLINDER_HIGH, cylmsb);
257
258    if (pc386_ide_show)
259    {
260      printk("IDE%d:%s: status=%02x\n", minor, label, status);
261      printk("IDE%d:%s: error=%02x\n", minor, label, error);
262      printk("IDE%d:%s: cylinder-low=%02x\n", minor, label, cyllsb);
263      printk("IDE%d:%s: cylinder-high=%02x\n", minor, label, cylmsb);
264    }
265
266    outport_byte(port+IDE_REGISTER_COMMAND, 0xec);
267
268    if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
269                                &status, pc386_ide_prestart_sleep))
270    {
271      if (pc386_ide_show)
272        printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
273      continue;
274    }
275
276    data_ready = pc386_ide_status_data_ready (port,
277                                              250,
278                                              &status,
279                                              pc386_ide_prestart_sleep);
280
281    if (status & IDE_REGISTER_STATUS_ERR)
282    {
283      inport_byte(port+IDE_REGISTER_ERROR, error);
284      if (error != 4)
285      {
286        if (pc386_ide_show)
287          printk("IDE%d:%s: error=%04x\n", minor, label, error);
288        continue;
289      }
290      /*
291       * The device is an ATAPI device.
292       */
293      outport_byte(port+IDE_REGISTER_COMMAND, 0xa1);
294      data_ready = pc386_ide_status_data_ready (port,
295                                                250,
296                                                &status,
297                                                pc386_ide_prestart_sleep);
298    }
299
300    if (!data_ready)
301      continue;
302
303    byte = 0;
304    while (byte < 512)
305    {
306      uint16_t word;
307
308      if (pc386_ide_show && ((byte % 16) == 0))
309        printk("\n %04" PRIx32 " : ", byte);
310
311      inport_word(port+IDE_REGISTER_DATA, word);
312
313      if (pc386_ide_show)
314        printk ("%04x ", word);
315
316      if (byte == 2)
317        cylinders = word;
318      if (byte == 6)
319        heads = word;
320      if (byte == 12)
321        sectors = word;
322
323      if (byte >= 54 && byte < (54 + 40))
324      {
325        *p = word >> 8;
326        p++;
327        *p = word;
328        p++;
329      }
330
331      if (byte == (47 * 2))
332        max_multiple_sectors = word & 0xff;
333
334      if (byte == (49 * 2))
335        capabilities = word;
336
337      if (byte == (59 * 2))
338      {
339        if (word & (1 << 8))
340          cur_multiple_sectors = word & 0xff;
341      }
342
343      if (byte == (60 * 2))
344        lba_sectors = word;
345      if (byte == (61 * 2))
346        lba_sectors |= word << 16;
347
348      byte += 2;
349    }
350
351    if (pc386_ide_show)
352      printk("\nbytes read = %" PRIu32 "\n", byte);
353
354    if (p != &model_number[0])
355    {
356      uint32_t size;
357      uint32_t left;
358      uint32_t right;
359      char     units;
360
361      if (capabilities & (1 << 9))
362        size = lba_sectors;
363      else
364        size = cylinders * heads * sectors;
365
366      size /= 2;
367
368      if (size > (1024 * 1024))
369      {
370        size = (size * 10) / (1000 * 1000);
371        units = 'G';
372      }
373      else if (size > 1024)
374      {
375        size = (size * 10) / 1000;
376        units = 'M';
377      }
378      else
379      {
380        size = size * 10;
381        units = 'K';
382      }
383
384      left = size / 10;
385      right = size % 10;
386
387      p--;
388      while (*p == ' ')
389      {
390        *p = '\0';
391        p--;
392      }
393
394      printk("IDE%d:%s:%s, %" PRIu32 ".%" PRIu32 "%c (%" PRIu32 "/%" PRIu32 "/%" PRIu32 "), max blk size:%d\n",
395             minor, label, model_number, left, right, units,
396             heads, cylinders, sectors, max_multiple_sectors * 512);
397    }
398
399#if IDE_CLEAR_MULTI_SECTOR_COUNT
400    if (max_multiple_sectors)
401    {
402      outport_byte(port+IDE_REGISTER_SECTOR_COUNT, 0);
403      outport_byte(port+IDE_REGISTER_COMMAND, 0xc6);
404
405      if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
406                                  &status, pc386_ide_prestart_sleep))
407      {
408        if (pc386_ide_show)
409          printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
410        continue;
411      }
412
413      inport_byte(port+IDE_REGISTER_STATUS, status);
414      if (status & IDE_REGISTER_STATUS_ERR)
415      {
416        inport_byte(port+IDE_REGISTER_ERROR, error);
417        if (error & IDE_REGISTER_ERROR_ABRT)
418          printk("IDE%d:%s: disable multiple failed\n", minor, label);
419        else
420          printk("IDE%d:%s: unknown error on disable multiple: %02x\n",
421                 minor, label, error);
422      }
423    }
424#endif
425
426    outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
427                 IDE_REGISTER_DEVICE_CONTROL_nIEN);
428    wait(10000);
429  }
430
431  pc386_ide_timeout = PC386_IDE_TASKING_TIMEOUT;
432
433  /*
434   * FIXME: enable interrupts, if needed
435   */
436}
437
438/*=========================================================================*\
439| Function:                                                                 |
440\*-------------------------------------------------------------------------*/
441static void pc386_ide_read_reg
442(
443/*-------------------------------------------------------------------------*\
444| Purpose:                                                                  |
445|  read a IDE controller register                                           |
446+---------------------------------------------------------------------------+
447| Input Parameters:                                                         |
448\*-------------------------------------------------------------------------*/
449 int                        minor,  /* controller minor number       */
450 int                        reg,    /* register index to access      */
451 uint16_t                  *value   /* ptr to return value location  */
452 )
453/*-------------------------------------------------------------------------*\
454| Return Value:                                                             |
455|    <none>                                                                 |
456\*=========================================================================*/
457{
458  uint32_t    port = IDE_Controller_Table[minor].port1;
459  uint8_t   bval1,bval2;
460
461  if (reg == IDE_REGISTER_DATA_WORD) {
462    inport_byte(port+reg, bval1);
463    inport_byte(port+reg+1, bval2);
464    *value = bval1 + (bval2 << 8);
465  }
466  else {
467    inport_byte(port+reg, bval1);
468    *value = bval1;
469  }
470#if PC386_IDE_DEBUG_OUT
471  pc386_ide_printk("pc386_ide_read_reg (0x%x)=0x%x\r\n",reg,*value & 0xff);
472#endif
473}
474
475/*=========================================================================*\
476| Function:                                                                 |
477\*-------------------------------------------------------------------------*/
478static void pc386_ide_write_reg
479(
480/*-------------------------------------------------------------------------*\
481| Purpose:                                                                  |
482|  write a IDE controller register                                          |
483+---------------------------------------------------------------------------+
484| Input Parameters:                                                         |
485\*-------------------------------------------------------------------------*/
486 int                        minor,  /* controller minor number       */
487 int                        reg,    /* register index to access      */
488 uint16_t                   value   /* value to write                */
489 )
490/*-------------------------------------------------------------------------*\
491| Return Value:                                                             |
492|    <none>                                                                 |
493\*=========================================================================*/
494{
495  uint32_t    port = IDE_Controller_Table[minor].port1;
496
497#if PC386_IDE_DEBUG_OUT
498  pc386_ide_printk("pc386_ide_write_reg(0x%x,0x%x)\r\n",reg,value & 0xff);
499#endif
500  if (reg == IDE_REGISTER_DATA_WORD) {
501    outport_word(port+reg,value);
502  }
503  else {
504    outport_byte(port+reg,value);
505  }
506}
507
508/*=========================================================================*\
509| Function:                                                                 |
510\*-------------------------------------------------------------------------*/
511static void pc386_ide_read_block
512(
513/*-------------------------------------------------------------------------*\
514| Purpose:                                                                  |
515|  read a IDE controller data block                                         |
516+---------------------------------------------------------------------------+
517| Input Parameters:                                                         |
518\*-------------------------------------------------------------------------*/
519 int                     minor,
520 uint32_t                block_size,
521 rtems_blkdev_sg_buffer *bufs,
522 uint32_t               *cbuf,
523 uint32_t               *pos
524 )
525/*-------------------------------------------------------------------------*\
526| Return Value:                                                             |
527|    <none>                                                                 |
528\*=========================================================================*/
529{
530  uint32_t port = IDE_Controller_Table[minor].port1;
531  uint32_t cnt = 0;
532#if PC386_IDE_DEBUG_OUT
533  int i32 = 0;
534  pc386_ide_printk("pc386_ide_read_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
535                   block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
536#endif
537
538  while (cnt < block_size)
539  {
540    uint16_t *lbuf;
541    uint8_t  status_val;
542    int      b;
543
544    if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
545                                      &status_val, pc386_ide_tasking_sleep))
546    {
547      printk ("pc386_ide_read_block: block=%" PRIu32 \
548              " cbuf=%" PRIu32 " status=%02x, cnt=%" PRIu32 " bs=%" PRIu32 "\n",
549              bufs[*cbuf].block, *cbuf, status_val, cnt, block_size);
550      /* FIXME: add an error here. */
551      return;
552    }
553
554    if (status_val & IDE_REGISTER_STATUS_ERR)
555    {
556      inport_byte(port+IDE_REGISTER_ERROR, status_val);
557      printk("pc386_ide_read_block: error: %02x\n", status_val);
558      return;
559    }
560
561    lbuf = (uint16_t*)((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
562
563    for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
564    {
565      inport_word(port+IDE_REGISTER_DATA,*lbuf);
566
567#if PC386_IDE_DEBUG_OUT
568      pc386_ide_printk("%04x ",*lbuf);
569      i32++;
570      if (i32 >= 16)
571      {
572        pc386_ide_printk("\n");
573        i32 = 0;
574      }
575#endif
576      lbuf++;
577    }
578    cnt    += ATA_SECTOR_SIZE;
579    (*pos) += ATA_SECTOR_SIZE;
580    if ((*pos) == bufs[(*cbuf)].length) {
581      (*pos) = 0;
582      (*cbuf)++;
583      lbuf = bufs[(*cbuf)].buffer;
584    }
585  }
586}
587
588/*=========================================================================*\
589| Function:                                                                 |
590\*-------------------------------------------------------------------------*/
591static void pc386_ide_write_block
592(
593/*-------------------------------------------------------------------------*\
594| Purpose:                                                                  |
595|  write a IDE controller data block                                        |
596+---------------------------------------------------------------------------+
597| Input Parameters:                                                         |
598\*-------------------------------------------------------------------------*/
599 int minor,
600 uint32_t                block_size,
601 rtems_blkdev_sg_buffer *bufs,
602 uint32_t               *cbuf,
603 uint32_t               *pos
604 )
605/*-------------------------------------------------------------------------*\
606| Return Value:                                                             |
607|    <none>                                                                 |
608\*=========================================================================*/
609{
610  uint32_t port = IDE_Controller_Table[minor].port1;
611  uint32_t cnt = 0;
612#if PC386_IDE_DEBUG_OUT
613  int i32 = 0;
614  pc386_ide_printk("pc386_ide_write_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
615                   block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
616#endif
617
618  while (cnt < block_size)
619  {
620    uint16_t *lbuf;
621    uint8_t  status_val;
622    int      b;
623
624    if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
625                                      &status_val, pc386_ide_tasking_sleep))
626    {
627      printk ("pc386_ide_write_block: block=%" PRIu32 " status=%02x, cnt=%" PRIu32 " bs=%" PRIu32 "\n",
628              bufs[*cbuf].block, status_val, cnt, block_size);
629      /* FIXME: add an error here. */
630      return;
631    }
632
633    if (status_val & IDE_REGISTER_STATUS_ERR)
634    {
635      inport_byte(port+IDE_REGISTER_ERROR, status_val);
636      printk ("pc386_ide_write_block: error: %02x\n", status_val);
637      return;
638    }
639
640    lbuf = (uint16_t*)(((uint8_t*)bufs[*cbuf].buffer) + (*pos));
641
642    for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
643    {
644#if PC386_IDE_DEBUG_OUT
645      pc386_ide_printk("%04x ",*lbuf);
646      i32++;
647      if (i32 >= 16)
648      {
649        pc386_ide_printk("\n");
650        i32 = 0;
651      }
652#endif
653      outport_word(port+IDE_REGISTER_DATA,*lbuf);
654      lbuf++;
655    }
656    cnt    += ATA_SECTOR_SIZE;
657    (*pos) += ATA_SECTOR_SIZE;
658    if ((*pos) == bufs[(*cbuf)].length) {
659      (*pos) = 0;
660      (*cbuf)++;
661      lbuf = bufs[(*cbuf)].buffer;
662    }
663  }
664}
665
666/*=========================================================================*\
667| Function:                                                                 |
668\*-------------------------------------------------------------------------*/
669static int pc386_ide_control
670(
671/*-------------------------------------------------------------------------*\
672| Purpose:                                                                  |
673|  control interface for controller                                         |
674+---------------------------------------------------------------------------+
675| Input Parameters:                                                         |
676\*-------------------------------------------------------------------------*/
677 int  minor,                        /* controller minor number       */
678 uint32_t   cmd,                    /* command to send               */
679 void * arg                         /* optional argument             */
680 )
681/*-------------------------------------------------------------------------*\
682| Return Value:                                                             |
683|    <none>                                                                 |
684\*=========================================================================*/
685{
686  return 0;
687}
688
689/*=========================================================================*\
690| Function:                                                                 |
691\*-------------------------------------------------------------------------*/
692static rtems_status_code pc386_ide_config_io_speed
693(
694/*-------------------------------------------------------------------------*\
695| Purpose:                                                                  |
696|  set up transfer speed, if possible                                       |
697+---------------------------------------------------------------------------+
698| Input Parameters:                                                         |
699\*-------------------------------------------------------------------------*/
700 int        minor,                   /* controller minor number       */
701 uint16_t   modes_avail              /* optional argument             */
702 )
703/*-------------------------------------------------------------------------*\
704| Return Value:                                                             |
705|    rtems_status_code                                                      |
706\*=========================================================================*/
707{
708  return RTEMS_SUCCESSFUL;
709}
710
711/*
712 * The following table configures the functions used for IDE drivers
713 * in this BSP.
714 */
715
716ide_ctrl_fns_t pc386_ide_ctrl_fns = {
717  pc386_ide_probe,
718  pc386_ide_initialize,
719  pc386_ide_control,
720  pc386_ide_read_reg,
721  pc386_ide_write_reg,
722  pc386_ide_read_block,
723  pc386_ide_write_block,
724  pc386_ide_config_io_speed
725};
Note: See TracBrowser for help on using the repository browser.