]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/mips/cavium/octeon_ebt3000_cf.c
Merge MIPS platform support to 8-STABLE.
[FreeBSD/stable/8.git] / sys / mips / cavium / octeon_ebt3000_cf.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
13  *      * Redistributions in binary form must reproduce the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer in the documentation and/or other materials provided
16  *        with the distribution.
17  *
18  *      * Neither the name of Cavium Networks nor the names of
19  *        its contributors may be used to endorse or promote products
20  *        derived from this software without specific prior written
21  *        permission.
22  *
23  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39 /*
40  *  octeon_ebt3000_cf.c
41  *
42  */
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include <sys/param.h>
48 #include <sys/bio.h>
49 #include <sys/systm.h>
50 #include <sys/sysctl.h>
51 #include <sys/ata.h>
52 #include <sys/bus.h>
53 #include <sys/kernel.h>
54 #include <sys/module.h>
55 #include <sys/rman.h>
56 #include <sys/power.h>
57 #include <sys/smp.h>
58 #include <sys/time.h>
59 #include <sys/timetc.h>
60 #include <sys/malloc.h>
61
62 #include <geom/geom.h>
63
64 #include <machine/clock.h>
65 #include <machine/locore.h>
66 #include <machine/md_var.h>
67 #include <machine/cpuregs.h>
68
69 #include <mips/cavium/octeon_pcmap_regs.h>
70
71 #include <contrib/octeon-sdk/cvmx.h>
72
73 /* ATA Commands */
74 #define CMD_READ_SECTOR         0x20
75 #define CMD_WRITE_SECTOR        0x30
76 #define CMD_IDENTIFY            0xEC
77
78 /* The ATA Task File */
79 #define TF_DATA                 0x00
80 #define TF_ERROR                0x01
81 #define TF_PRECOMP              0x01
82 #define TF_SECTOR_COUNT         0x02
83 #define TF_SECTOR_NUMBER        0x03
84 #define TF_CYL_LSB              0x04
85 #define TF_CYL_MSB              0x05
86 #define TF_DRV_HEAD             0x06
87 #define TF_STATUS               0x07
88 #define TF_COMMAND              0x07
89
90 /* Status Register */
91 #define STATUS_BSY              0x80    /* Drive is busy */
92 #define STATUS_RDY              0x40    /* Drive is ready */
93 #define STATUS_DF               0x20    /* Device fault */
94 #define STATUS_DRQ              0x08    /* Data can be transferred */
95
96 /* Miscelaneous */
97 #define SECTOR_SIZE             512
98 #define WAIT_DELAY              1000
99 #define NR_TRIES                1000
100 #define SWAP_SHORT(x)           ((x << 8) | (x >> 8))
101 #define MODEL_STR_SIZE          40
102
103 /* XXX */
104 extern cvmx_bootinfo_t *octeon_bootinfo;
105
106 /* Globals */
107 int     bus_width;
108 void    *base_addr;
109
110 /* Device softc */
111 struct cf_priv {
112
113         device_t dev;
114         struct drive_param *drive_param;
115
116         struct bio_queue_head cf_bq;
117         struct g_geom *cf_geom;
118         struct g_provider *cf_provider;
119
120 };
121
122 /* Device parameters */
123 struct drive_param{
124         union {
125                 char buf[SECTOR_SIZE];
126                 struct ata_params driveid;
127         } u;
128
129         char model[MODEL_STR_SIZE];
130         uint32_t nr_sectors;
131         uint16_t sector_size;
132         uint16_t heads;
133         uint16_t tracks;
134         uint16_t sec_track;
135
136 } drive_param;
137
138 /* GEOM class implementation */
139 static g_access_t       cf_access;
140 static g_start_t        cf_start;
141 static g_ioctl_t        cf_ioctl;
142
143 struct g_class g_cf_class = {
144         .name =         "CF",
145         .version =      G_VERSION,
146         .start =        cf_start,
147         .access =       cf_access,
148         .ioctl =        cf_ioctl,
149 };
150
151 DECLARE_GEOM_CLASS(g_cf_class, g_cf);
152
153 /* Device methods */
154 static int      cf_probe(device_t);
155 static void     cf_identify(driver_t *, device_t);
156 static int      cf_attach(device_t);
157 static int      cf_attach_geom(void *, int);
158
159 /* ATA methods */
160 static int      cf_cmd_identify(void);
161 static int      cf_cmd_write(uint32_t, uint32_t, void *);
162 static int      cf_cmd_read(uint32_t, uint32_t, void *);
163 static int      cf_wait_busy(void);
164 static int      cf_send_cmd(uint32_t, uint8_t);
165 static void     cf_attach_geom_proxy(void *arg, int flag);
166
167 /* Miscelenous */
168 static void     cf_swap_ascii(unsigned char[], char[]);
169
170
171 /* ------------------------------------------------------------------- *
172  *                      cf_access()                                    *
173  * ------------------------------------------------------------------- */
174 static int cf_access (struct g_provider *pp, int r, int w, int e)
175 {
176
177         pp->sectorsize = drive_param.sector_size;
178         pp->stripesize = drive_param.heads * drive_param.sec_track * drive_param.sector_size;
179         pp->mediasize  = pp->stripesize * drive_param.tracks;
180
181         return (0);
182 }
183
184
185 /* ------------------------------------------------------------------- *
186  *                      cf_start()                                     *
187  * ------------------------------------------------------------------- */
188 static void cf_start (struct bio *bp)
189 {
190         int error;
191
192         /*
193         * Handle actual I/O requests. The request is passed down through
194         * the bio struct.
195         */
196
197         if(bp->bio_cmd & BIO_GETATTR) {
198                 if (g_handleattr_int(bp, "GEOM::fwsectors", drive_param.sec_track))
199                         return;
200                 if (g_handleattr_int(bp, "GEOM::fwheads",   drive_param.heads))
201                         return;
202                 g_io_deliver(bp, ENOIOCTL);
203                 return;
204         }
205
206         if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) {
207
208                 if (bp->bio_cmd & BIO_READ) {
209                         error = cf_cmd_read(bp->bio_length / drive_param.sector_size,
210                             bp->bio_offset / drive_param.sector_size, bp->bio_data);
211                 } else if (bp->bio_cmd & BIO_WRITE) {
212                         error = cf_cmd_write(bp->bio_length / drive_param.sector_size,
213                             bp->bio_offset/drive_param.sector_size, bp->bio_data);
214                 } else {
215                         printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd);
216                         error = ENOTSUP;
217                 }
218
219                 if (error != 0) {
220                         g_io_deliver(bp, error);
221                         return;
222                 }
223
224                 bp->bio_resid = 0;
225                 bp->bio_completed = bp->bio_length;
226                 g_io_deliver(bp, 0);
227         }
228 }
229
230
231 static int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
232 {
233     return (0);
234 }
235
236
237 /* ------------------------------------------------------------------- *
238  *                      cf_cmd_read()                                  *
239  * ------------------------------------------------------------------- *
240  *
241  *  Read nr_sectors from the device starting from start_sector.
242  */
243 static int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf)
244 {
245         unsigned long lba;
246         uint32_t count;
247         uint16_t *ptr_16;
248         uint8_t  *ptr_8;
249         int error;
250
251 //#define OCTEON_VISUAL_CF_0 1
252 #ifdef OCTEON_VISUAL_CF_0
253         octeon_led_write_char(0, 'R');
254 #endif
255         ptr_8  = (uint8_t*)buf;
256         ptr_16 = (uint16_t*)buf;
257         lba = start_sector; 
258
259
260         while (nr_sectors--) {
261                 error = cf_send_cmd(lba, CMD_READ_SECTOR);
262                 if (error != 0) {
263                         printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error);
264                         return (error);
265                 }
266
267                 if (bus_width == 8) {
268                         volatile uint8_t *task_file = (volatile uint8_t*)base_addr;
269                         volatile uint8_t dummy;
270                         for (count = 0; count < SECTOR_SIZE; count++) {
271                                 *ptr_8++ = task_file[TF_DATA];
272                                 if ((count & 0xf) == 0) dummy = task_file[TF_STATUS];
273                         }
274                 } else {
275                         volatile uint16_t *task_file = (volatile uint16_t*)base_addr;
276                         volatile uint16_t dummy;
277                         for (count = 0; count < SECTOR_SIZE; count+=2) {
278                                 uint16_t temp;
279                                 temp = task_file[TF_DATA];
280                                 *ptr_16++ = SWAP_SHORT(temp);
281                                 if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2];
282                         }
283                 }  
284
285                 lba ++;
286         }
287 #ifdef OCTEON_VISUAL_CF_0
288         octeon_led_write_char(0, ' ');
289 #endif
290         return (0);
291 }
292
293
294 /* ------------------------------------------------------------------- *
295  *                      cf_cmd_write()                                 *
296  * ------------------------------------------------------------------- *
297  *
298  * Write nr_sectors to the device starting from start_sector.
299  */
300 static int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf)
301 {
302         uint32_t lba;
303         uint32_t count;
304         uint16_t *ptr_16;
305         uint8_t  *ptr_8;
306         int error;
307         
308 //#define OCTEON_VISUAL_CF_1 1
309 #ifdef OCTEON_VISUAL_CF_1
310         octeon_led_write_char(1, 'W');
311 #endif
312         lba = start_sector;
313         ptr_8  = (uint8_t*)buf;
314         ptr_16 = (uint16_t*)buf;
315
316         while (nr_sectors--) {
317                 error = cf_send_cmd(lba, CMD_WRITE_SECTOR);
318                 if (error != 0) {
319                         printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error);
320                         return (error);
321                 }
322
323                 if (bus_width == 8) {
324                         volatile uint8_t *task_file;
325                         volatile uint8_t dummy;
326
327                         task_file = (volatile uint8_t *) base_addr;
328                         for (count = 0; count < SECTOR_SIZE; count++) {
329                                 task_file[TF_DATA] =  *ptr_8++;
330                                 if ((count & 0xf) == 0) dummy = task_file[TF_STATUS];
331                         }
332                 } else {
333                         volatile uint16_t *task_file;
334                         volatile uint16_t dummy;
335
336                         task_file = (volatile uint16_t *) base_addr;
337                         for (count = 0; count < SECTOR_SIZE; count+=2) {
338                                 uint16_t temp = *ptr_16++;
339                                 task_file[TF_DATA] =  SWAP_SHORT(temp);
340                                 if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2];
341                         }
342                 } 
343
344                 lba ++;
345         }
346 #ifdef OCTEON_VISUAL_CF_1
347         octeon_led_write_char(1, ' ');
348 #endif
349         return (0);
350 }
351
352
353 /* ------------------------------------------------------------------- *
354  *                      cf_cmd_identify()                              *
355  * ------------------------------------------------------------------- *
356  *
357  * Read parameters and other information from the drive and store 
358  * it in the drive_param structure
359  *
360  */
361 static int cf_cmd_identify (void)
362 {
363         int count;
364         uint8_t status;
365         int error;
366
367         if (bus_width == 8) {
368                 volatile uint8_t *task_file;
369
370                 task_file = (volatile uint8_t *) base_addr;
371
372                 while ((status = task_file[TF_STATUS]) & STATUS_BSY) {
373                         DELAY(WAIT_DELAY);
374                 }
375
376                 task_file[TF_SECTOR_COUNT]  = 0;
377                 task_file[TF_SECTOR_NUMBER] = 0;
378                 task_file[TF_CYL_LSB]  = 0;
379                 task_file[TF_CYL_MSB]  = 0;
380                 task_file[TF_DRV_HEAD] = 0;
381                 task_file[TF_COMMAND]  = CMD_IDENTIFY;
382
383                 error = cf_wait_busy();
384                 if (error == 0) {
385                         for (count = 0; count < SECTOR_SIZE; count++) 
386                                 drive_param.u.buf[count] = task_file[TF_DATA];
387                 }
388         } else {
389                 volatile uint16_t *task_file;
390
391                 task_file = (volatile uint16_t *) base_addr;
392
393                 while ((status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) {
394                         DELAY(WAIT_DELAY);
395                 }
396
397                 task_file[TF_SECTOR_COUNT/2]  = 0; /* this includes TF_SECTOR_NUMBER */
398                 task_file[TF_CYL_LSB/2]  = 0; /* this includes TF_CYL_MSB */
399                 task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */
400
401                 error = cf_wait_busy();
402                 if (error == 0) {
403                         for (count = 0; count < SECTOR_SIZE; count+=2) {
404                                 uint16_t temp;
405                                 temp = task_file[TF_DATA];
406                                 
407                                 /* endianess will be swapped below */
408                                 drive_param.u.buf[count]   = (temp & 0xff);
409                                 drive_param.u.buf[count+1] = (temp & 0xff00)>>8;
410                         }
411                 }
412         }
413         if (error != 0) {
414                 printf("%s: identify failed: %d\n", __func__, error);
415                 return (error);
416         }
417
418         cf_swap_ascii(drive_param.u.driveid.model, drive_param.model);
419
420         drive_param.sector_size =  512;   //=  SWAP_SHORT (drive_param.u.driveid.sector_bytes);
421         drive_param.heads       =  SWAP_SHORT (drive_param.u.driveid.current_heads);
422         drive_param.tracks      =  SWAP_SHORT (drive_param.u.driveid.current_cylinders); 
423         drive_param.sec_track   =  SWAP_SHORT (drive_param.u.driveid.current_sectors);
424         drive_param.nr_sectors  = (uint32_t)SWAP_SHORT (drive_param.u.driveid.lba_size_1) |
425             ((uint32_t)SWAP_SHORT (drive_param.u.driveid.lba_size_2));
426
427         return (0);
428 }
429
430
431 /* ------------------------------------------------------------------- *
432  *                      cf_send_cmd()                                  *
433  * ------------------------------------------------------------------- *
434  *
435  * Send command to read/write one sector specified by lba.
436  *
437  */
438 static int cf_send_cmd (uint32_t lba, uint8_t cmd)
439 {
440         uint8_t status;
441
442         if (bus_width == 8) {
443                 volatile uint8_t *task_file;
444
445                 task_file = (volatile uint8_t *) base_addr;
446
447                 while ( (status = task_file[TF_STATUS]) & STATUS_BSY) {
448                         DELAY(WAIT_DELAY);
449                 }
450
451                 task_file[TF_SECTOR_COUNT]  = 1;
452                 task_file[TF_SECTOR_NUMBER] = (lba & 0xff);
453                 task_file[TF_CYL_LSB]  =  ((lba >> 8) & 0xff);
454                 task_file[TF_CYL_MSB]  =  ((lba >> 16) & 0xff);
455                 task_file[TF_DRV_HEAD] =  ((lba >> 24) & 0xff) | 0xe0; 
456                 task_file[TF_COMMAND]  =  cmd;
457
458         } else {
459                 volatile uint16_t *task_file;
460
461                 task_file = (volatile uint16_t *) base_addr;
462
463                 while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) {
464                         DELAY(WAIT_DELAY);
465                 }
466
467                 task_file[TF_SECTOR_COUNT/2]  = 1 | ((lba & 0xff) << 8);
468                 task_file[TF_CYL_LSB/2]  =  ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8);
469                 task_file[TF_DRV_HEAD/2] =  (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8); 
470
471         }
472
473         return (cf_wait_busy());
474 }
475
476 /* ------------------------------------------------------------------- *
477  *                      cf_wait_busy()                                 *
478  * ------------------------------------------------------------------- *
479  *
480  * Wait until the drive finishes a given command and data is
481  * ready to be transferred. This is done by repeatedly checking 
482  * the BSY bit of the status register. When the controller is ready for
483  * data transfer, it clears the BSY bit and sets the DRQ bit.
484  *
485  * If the DF bit is ever set, we return error.
486  *
487  * This code originally spun on DRQ.  If that behavior turns out to be
488  * necessary, a flag can be added or this function can be called
489  * repeatedly as long as it is returning ENXIO.
490  */
491 static int cf_wait_busy (void)
492 {
493         uint8_t status;
494
495 //#define OCTEON_VISUAL_CF_2 1
496 #ifdef OCTEON_VISUAL_CF_2
497         static int where0 = 0;
498
499         octeon_led_run_wheel(&where0, 2);
500 #endif
501
502         if (bus_width == 8) {
503                 volatile uint8_t *task_file;
504                 task_file = (volatile uint8_t *)base_addr;
505
506                 status = task_file[TF_STATUS];  
507                 while ((status & STATUS_BSY) == STATUS_BSY) {
508                         if ((status & STATUS_DF) != 0) {
509                                 printf("%s: device fault (status=%x)\n", __func__, status);
510                                 return (EIO);
511                         }
512                         DELAY(WAIT_DELAY);
513                         status = task_file[TF_STATUS];
514                 }
515         } else {
516                 volatile uint16_t *task_file;
517                 task_file = (volatile uint16_t *)base_addr;
518
519                 status = task_file[TF_STATUS/2]>>8;     
520                 while ((status & STATUS_BSY) == STATUS_BSY) {
521                         if ((status & STATUS_DF) != 0) {
522                                 printf("%s: device fault (status=%x)\n", __func__, status);
523                                 return (EIO);
524                         }
525                         DELAY(WAIT_DELAY);
526                         status = (uint8_t)(task_file[TF_STATUS/2]>>8);
527                 }
528         }
529         if ((status & STATUS_DRQ) == 0) {
530                 printf("%s: device not ready (status=%x)\n", __func__, status);
531                 return (ENXIO);
532         }
533
534 #ifdef OCTEON_VISUAL_CF_2
535         octeon_led_write_char(2, ' ');
536 #endif
537         return (0);
538 }
539
540 /* ------------------------------------------------------------------- *
541  *                      cf_swap_ascii()                                *
542  * ------------------------------------------------------------------- *
543  *
544  * The ascii string returned by the controller specifying 
545  * the model of the drive is byte-swaped. This routine 
546  * corrects the byte ordering.
547  *
548  */
549 static void cf_swap_ascii (unsigned char str1[], char str2[])
550 {
551         int i;
552
553         for(i = 0; i < MODEL_STR_SIZE; i++) {
554             str2[i] = str1[i^1];
555         }
556 }
557
558
559 /* ------------------------------------------------------------------- *
560  *                      cf_probe()                                     *
561  * ------------------------------------------------------------------- */
562
563 static int cf_probe (device_t dev)
564 {
565         if (octeon_is_simulation()) return 1;
566
567         if (device_get_unit(dev) != 0) {
568                 panic("can't attach more devices\n");
569         }
570
571         device_set_desc(dev, "Octeon Compact Flash Driver");
572
573         return (cf_cmd_identify());
574 }
575
576 /* ------------------------------------------------------------------- *
577  *                      cf_identify()                                  *
578  * ------------------------------------------------------------------- *
579  *
580  * Find the bootbus region for the CF to determine 
581  * 16 or 8 bit and check to see if device is 
582  * inserted.
583  *
584  */
585 static void cf_identify (driver_t *drv, device_t parent)
586 {
587         uint8_t status;
588         int bus_region;
589         int count = 0;
590         cvmx_mio_boot_reg_cfgx_t cfg;
591
592         if (octeon_is_simulation())
593                 return;
594
595         base_addr = cvmx_phys_to_ptr(octeon_bootinfo->compact_flash_common_base_addr);
596
597         for (bus_region = 0; bus_region < 8; bus_region++)
598         {
599                 cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(bus_region));
600                 if (cfg.s.base == octeon_bootinfo->compact_flash_common_base_addr >> 16)
601                 {
602                         bus_width = (cfg.s.width) ? 16: 8;
603                         printf("Compact flash found in bootbus region %d (%d bit).\n", bus_region, bus_width);
604                         break;
605                 }
606         }
607
608         if (bus_width == 8) {
609                 volatile uint8_t *task_file;
610                 task_file = (volatile uint8_t *) base_addr;
611                 /* Check if CF is inserted */
612                 while ( (status = task_file[TF_STATUS]) & STATUS_BSY){
613                         if ((count++) == NR_TRIES )     {
614                                 printf("Compact Flash not present\n");
615                                 return;
616                         }
617                         DELAY(WAIT_DELAY);
618                 }
619         } else {
620                 volatile uint16_t *task_file;
621                 task_file = (volatile uint16_t *) base_addr;
622                 /* Check if CF is inserted */
623                 while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY){
624                         if ((count++) == NR_TRIES )     {
625                                 printf("Compact Flash not present\n");
626                                 return;
627                         }
628                         DELAY(WAIT_DELAY);
629                 }
630         }
631
632         BUS_ADD_CHILD(parent, 0, "cf", 0);
633 }
634
635
636 /* ------------------------------------------------------------------- *
637  *                      cf_attach_geom()                               *
638  * ------------------------------------------------------------------- */
639
640 static int cf_attach_geom (void *arg, int flag)
641 {
642         struct cf_priv *cf_priv;
643
644         cf_priv = (struct cf_priv *) arg;
645         cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev));
646         cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name);
647         cf_priv->cf_geom->softc = cf_priv;
648         g_error_provider(cf_priv->cf_provider, 0);
649
650         return (0);
651 }
652
653 /* ------------------------------------------------------------------- *
654  *                      cf_attach_geom()                               *
655  * ------------------------------------------------------------------- */
656 static void cf_attach_geom_proxy (void *arg, int flag)
657 {
658     cf_attach_geom(arg, flag);
659 }
660
661
662
663 /* ------------------------------------------------------------------- *
664  *                      cf_attach()                                    *
665  * ------------------------------------------------------------------- */
666
667 static int cf_attach (device_t dev)
668 {
669         struct cf_priv *cf_priv;
670
671         if (octeon_is_simulation()) return 1;
672
673         cf_priv = device_get_softc(dev);
674         cf_priv->dev = dev;
675         cf_priv->drive_param = &drive_param;
676
677         g_post_event(cf_attach_geom_proxy, cf_priv, M_WAITOK, NULL);
678         bioq_init(&cf_priv->cf_bq);
679
680         return 0;
681 }
682
683
684 static device_method_t cf_methods[] = {
685         /* Device interface */
686         DEVMETHOD(device_probe,         cf_probe),
687         DEVMETHOD(device_identify,      cf_identify),
688         DEVMETHOD(device_attach,        cf_attach),
689         DEVMETHOD(device_detach,        bus_generic_detach),
690         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
691
692         { 0, 0 }
693 };
694
695 static driver_t cf_driver = {
696         "cf", 
697         cf_methods, 
698         sizeof(struct cf_priv)
699 };
700
701 static devclass_t cf_devclass;
702
703 DRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0);
704