octeon_ebt3000_cf.c revision 194149
1194149Simp/* 2194149Simp * octeon_ebt3000_cf.c 3194149Simp * 4194149Simp */ 5194149Simp 6194149Simp#include <sys/cdefs.h> 7194149Simp__FBSDID("$FreeBSD: projects/mips/sys/dev/flash/octeon_ebt3000_cf.c 194149 2009-06-14 03:47:44Z imp $"); 8194149Simp 9194149Simp#include <sys/param.h> 10194149Simp#include <sys/bio.h> 11194149Simp#include <sys/systm.h> 12194149Simp#include <sys/sysctl.h> 13194149Simp#include <sys/bus.h> 14194149Simp#include <sys/kernel.h> 15194149Simp#include <sys/module.h> 16194149Simp#include <sys/rman.h> 17194149Simp#include <sys/power.h> 18194149Simp#include <sys/smp.h> 19194149Simp#include <sys/time.h> 20194149Simp#include <sys/timetc.h> 21194149Simp#include <sys/malloc.h> 22194149Simp 23194149Simp#include <geom/geom.h> 24194149Simp 25194149Simp#include <machine/clock.h> 26194149Simp#include <machine/locore.h> 27194149Simp#include <machine/md_var.h> 28194149Simp#include <machine/cpuregs.h> 29194149Simp 30194149Simp#include "octeon_ebt3000_cf.h" 31194149Simp#include "driveid.h" 32194149Simp 33194149Simp/* ATA Commands */ 34194149Simp#define CMD_READ_SECTOR 0x20 35194149Simp#define CMD_WRITE_SECTOR 0x30 36194149Simp#define CMD_IDENTIFY 0xEC 37194149Simp 38194149Simp/* The ATA Task File */ 39194149Simp#define TF_DATA 0x00 40194149Simp#define TF_ERROR 0x01 41194149Simp#define TF_PRECOMP 0x01 42194149Simp#define TF_SECTOR_COUNT 0x02 43194149Simp#define TF_SECTOR_NUMBER 0x03 44194149Simp#define TF_CYL_LSB 0x04 45194149Simp#define TF_CYL_MSB 0x05 46194149Simp#define TF_DRV_HEAD 0x06 47194149Simp#define TF_STATUS 0x07 48194149Simp#define TF_COMMAND 0x07 49194149Simp 50194149Simp/* Status Register */ 51194149Simp#define STATUS_BSY 0x80 /* Drive is busy */ 52194149Simp#define STATUS_RDY 0x40 /* Drive is ready */ 53194149Simp#define STATUS_DRQ 0x08 /* Data can be transferred */ 54194149Simp 55194149Simp/* Miscelaneous */ 56194149Simp#define SECTOR_SIZE 512 57194149Simp#define WAIT_DELAY 1000 58194149Simp#define NR_TRIES 1000 59194149Simp#define SWAP_SHORT(x) ((x << 8) | (x >> 8)) 60194149Simp#define SWAP_LONG(x) (((x << 24) & 0xFF000000) | ((x << 8) & 0x00FF0000) | \ 61194149Simp ((x >> 8) & 0x0000FF00) | ((x << 24) & 0x000000FF) ) 62194149Simp#define MODEL_STR_SIZE 40 63194149Simp 64194149Simp 65194149Simp/* Globals */ 66194149Simpint bus_width; 67194149Simpvoid *base_addr; 68194149Simp 69194149Simp/* Device softc */ 70194149Simpstruct cf_priv { 71194149Simp 72194149Simp device_t dev; 73194149Simp struct drive_param *drive_param; 74194149Simp 75194149Simp struct bio_queue_head cf_bq; 76194149Simp struct g_geom *cf_geom; 77194149Simp struct g_provider *cf_provider; 78194149Simp 79194149Simp}; 80194149Simp 81194149Simp/* Device parameters */ 82194149Simpstruct drive_param{ 83194149Simp union { 84194149Simp char buf[SECTOR_SIZE]; 85194149Simp struct hd_driveid driveid; 86194149Simp } u; 87194149Simp 88194149Simp char model[MODEL_STR_SIZE]; 89194149Simp uint32_t nr_sectors; 90194149Simp uint16_t sector_size; 91194149Simp uint16_t heads; 92194149Simp uint16_t tracks; 93194149Simp uint16_t sec_track; 94194149Simp 95194149Simp} drive_param; 96194149Simp 97194149Simp/* GEOM class implementation */ 98194149Simpstatic g_access_t cf_access; 99194149Simpstatic g_start_t cf_start; 100194149Simpstatic g_ioctl_t cf_ioctl; 101194149Simp 102194149Simpstruct g_class g_cf_class = { 103194149Simp .name = "CF", 104194149Simp .version = G_VERSION, 105194149Simp .start = cf_start, 106194149Simp .access = cf_access, 107194149Simp .ioctl = cf_ioctl, 108194149Simp}; 109194149Simp 110194149Simp/* Device methods */ 111194149Simpstatic int cf_probe(device_t); 112194149Simpstatic void cf_identify(driver_t *, device_t); 113194149Simpstatic int cf_attach(device_t); 114194149Simpstatic int cf_attach_geom(void *, int); 115194149Simp 116194149Simp/* ATA methods */ 117194149Simpstatic void cf_cmd_identify(void); 118194149Simpstatic void cf_cmd_write(uint32_t, uint32_t, void *); 119194149Simpstatic void cf_cmd_read(uint32_t, uint32_t, void *); 120194149Simpstatic void cf_wait_busy(void); 121194149Simpstatic void cf_send_cmd(uint32_t, uint8_t); 122194149Simpstatic void cf_attach_geom_proxy(void *arg, int flag); 123194149Simp 124194149Simp/* Miscelenous */ 125194149Simpstatic void cf_swap_ascii(unsigned char[], char[]); 126194149Simp 127194149Simp 128194149Simp/* ------------------------------------------------------------------- * 129194149Simp * cf_access() * 130194149Simp * ------------------------------------------------------------------- */ 131194149Simpstatic int cf_access (struct g_provider *pp, int r, int w, int e) 132194149Simp{ 133194149Simp 134194149Simp pp->sectorsize = drive_param.sector_size; 135194149Simp pp->stripesize = drive_param.heads * drive_param.sec_track * drive_param.sector_size; 136194149Simp pp->mediasize = pp->stripesize * drive_param.tracks; 137194149Simp 138194149Simp return (0); 139194149Simp} 140194149Simp 141194149Simp 142194149Simp/* ------------------------------------------------------------------- * 143194149Simp * cf_start() * 144194149Simp * ------------------------------------------------------------------- */ 145194149Simpstatic void cf_start (struct bio *bp) 146194149Simp{ 147194149Simp /* 148194149Simp * Handle actual I/O requests. The request is passed down through 149194149Simp * the bio struct. 150194149Simp */ 151194149Simp 152194149Simp if(bp->bio_cmd & BIO_GETATTR) { 153194149Simp if (g_handleattr_int(bp, "GEOM::fwsectors", drive_param.sec_track)) 154194149Simp return; 155194149Simp if (g_handleattr_int(bp, "GEOM::fwheads", drive_param.heads)) 156194149Simp return; 157194149Simp g_io_deliver(bp, ENOIOCTL); 158194149Simp return; 159194149Simp } 160194149Simp 161194149Simp if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { 162194149Simp 163194149Simp if (bp->bio_cmd & BIO_READ) { 164194149Simp cf_cmd_read(bp->bio_length / drive_param.sector_size, 165194149Simp bp->bio_offset / drive_param.sector_size, bp->bio_data); 166194149Simp 167194149Simp } else if (bp->bio_cmd & BIO_WRITE) { 168194149Simp cf_cmd_write(bp->bio_length / drive_param.sector_size, 169194149Simp bp->bio_offset/drive_param.sector_size, bp->bio_data); 170194149Simp } 171194149Simp 172194149Simp bp->bio_resid = 0; 173194149Simp bp->bio_completed = bp->bio_length; 174194149Simp g_io_deliver(bp, 0); 175194149Simp } 176194149Simp} 177194149Simp 178194149Simp 179194149Simpstatic int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 180194149Simp{ 181194149Simp return (0); 182194149Simp} 183194149Simp 184194149Simp 185194149Simp/* ------------------------------------------------------------------- * 186194149Simp * cf_cmd_read() * 187194149Simp * ------------------------------------------------------------------- * 188194149Simp * 189194149Simp * Read nr_sectors from the device starting from start_sector. 190194149Simp */ 191194149Simpstatic void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) 192194149Simp{ 193194149Simp unsigned long lba; 194194149Simp uint32_t count; 195194149Simp uint16_t *ptr_16; 196194149Simp uint8_t *ptr_8; 197194149Simp 198194149Simp//#define OCTEON_VISUAL_CF_0 1 199194149Simp#ifdef OCTEON_VISUAL_CF_0 200194149Simp octeon_led_write_char(0, 'R'); 201194149Simp#endif 202194149Simp ptr_8 = (uint8_t*)buf; 203194149Simp ptr_16 = (uint16_t*)buf; 204194149Simp lba = start_sector; 205194149Simp 206194149Simp 207194149Simp while (nr_sectors--) { 208194149Simp 209194149Simp cf_send_cmd(lba, CMD_READ_SECTOR); 210194149Simp 211194149Simp if (bus_width == 8) { 212194149Simp volatile uint8_t *task_file = (volatile uint8_t*)base_addr; 213194149Simp volatile uint8_t dummy; 214194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 215194149Simp *ptr_8++ = task_file[TF_DATA]; 216194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS]; 217194149Simp } 218194149Simp } else { 219194149Simp volatile uint16_t *task_file = (volatile uint16_t*)base_addr; 220194149Simp volatile uint16_t dummy; 221194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 222194149Simp uint16_t temp; 223194149Simp temp = task_file[TF_DATA]; 224194149Simp *ptr_16++ = SWAP_SHORT(temp); 225194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2]; 226194149Simp } 227194149Simp } 228194149Simp 229194149Simp lba ++; 230194149Simp } 231194149Simp#ifdef OCTEON_VISUAL_CF_0 232194149Simp octeon_led_write_char(0, ' '); 233194149Simp#endif 234194149Simp} 235194149Simp 236194149Simp 237194149Simp/* ------------------------------------------------------------------- * 238194149Simp * cf_cmd_write() * 239194149Simp * ------------------------------------------------------------------- * 240194149Simp * 241194149Simp * Write nr_sectors to the device starting from start_sector. 242194149Simp */ 243194149Simpstatic void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) 244194149Simp{ 245194149Simp uint32_t lba; 246194149Simp uint32_t count; 247194149Simp uint16_t *ptr_16; 248194149Simp uint8_t *ptr_8; 249194149Simp 250194149Simp//#define OCTEON_VISUAL_CF_1 1 251194149Simp#ifdef OCTEON_VISUAL_CF_1 252194149Simp octeon_led_write_char(1, 'W'); 253194149Simp#endif 254194149Simp lba = start_sector; 255194149Simp ptr_8 = (uint8_t*)buf; 256194149Simp ptr_16 = (uint16_t*)buf; 257194149Simp 258194149Simp while (nr_sectors--) { 259194149Simp 260194149Simp cf_send_cmd(lba, CMD_WRITE_SECTOR); 261194149Simp 262194149Simp if (bus_width == 8) { 263194149Simp volatile uint8_t *task_file; 264194149Simp volatile uint8_t dummy; 265194149Simp 266194149Simp task_file = (volatile uint8_t *) base_addr; 267194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 268194149Simp task_file[TF_DATA] = *ptr_8++; 269194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS]; 270194149Simp } 271194149Simp } else { 272194149Simp volatile uint16_t *task_file; 273194149Simp volatile uint16_t dummy; 274194149Simp 275194149Simp task_file = (volatile uint16_t *) base_addr; 276194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 277194149Simp uint16_t temp = *ptr_16++; 278194149Simp task_file[TF_DATA] = SWAP_SHORT(temp); 279194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2]; 280194149Simp } 281194149Simp } 282194149Simp 283194149Simp lba ++; 284194149Simp } 285194149Simp#ifdef OCTEON_VISUAL_CF_1 286194149Simp octeon_led_write_char(1, ' '); 287194149Simp#endif 288194149Simp} 289194149Simp 290194149Simp 291194149Simp/* ------------------------------------------------------------------- * 292194149Simp * cf_cmd_identify() * 293194149Simp * ------------------------------------------------------------------- * 294194149Simp * 295194149Simp * Read parameters and other information from the drive and store 296194149Simp * it in the drive_param structure 297194149Simp * 298194149Simp */ 299194149Simpstatic void cf_cmd_identify (void) 300194149Simp{ 301194149Simp int count; 302194149Simp uint8_t status; 303194149Simp 304194149Simp if (bus_width == 8) { 305194149Simp volatile uint8_t *task_file; 306194149Simp 307194149Simp task_file = (volatile uint8_t *) base_addr; 308194149Simp 309194149Simp while ((status = task_file[TF_STATUS]) & STATUS_BSY) { 310194149Simp DELAY(WAIT_DELAY); 311194149Simp } 312194149Simp 313194149Simp task_file[TF_SECTOR_COUNT] = 0; 314194149Simp task_file[TF_SECTOR_NUMBER] = 0; 315194149Simp task_file[TF_CYL_LSB] = 0; 316194149Simp task_file[TF_CYL_MSB] = 0; 317194149Simp task_file[TF_DRV_HEAD] = 0; 318194149Simp task_file[TF_COMMAND] = CMD_IDENTIFY; 319194149Simp 320194149Simp cf_wait_busy(); 321194149Simp 322194149Simp for (count = 0; count < SECTOR_SIZE; count++) 323194149Simp drive_param.u.buf[count] = task_file[TF_DATA]; 324194149Simp 325194149Simp } else { 326194149Simp volatile uint16_t *task_file; 327194149Simp 328194149Simp task_file = (volatile uint16_t *) base_addr; 329194149Simp 330194149Simp while ((status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) { 331194149Simp DELAY(WAIT_DELAY); 332194149Simp } 333194149Simp 334194149Simp task_file[TF_SECTOR_COUNT/2] = 0; /* this includes TF_SECTOR_NUMBER */ 335194149Simp task_file[TF_CYL_LSB/2] = 0; /* this includes TF_CYL_MSB */ 336194149Simp task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */ 337194149Simp 338194149Simp cf_wait_busy(); 339194149Simp 340194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 341194149Simp uint16_t temp; 342194149Simp temp = task_file[TF_DATA]; 343194149Simp 344194149Simp /* endianess will be swapped below */ 345194149Simp drive_param.u.buf[count] = (temp & 0xff); 346194149Simp drive_param.u.buf[count+1] = (temp & 0xff00)>>8; 347194149Simp } 348194149Simp } 349194149Simp 350194149Simp cf_swap_ascii(drive_param.u.driveid.model, drive_param.model); 351194149Simp 352194149Simp drive_param.sector_size = 512; //= SWAP_SHORT (drive_param.u.driveid.sector_bytes); 353194149Simp drive_param.heads = SWAP_SHORT (drive_param.u.driveid.cur_heads); 354194149Simp drive_param.tracks = SWAP_SHORT (drive_param.u.driveid.cur_cyls); 355194149Simp drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.cur_sectors); 356194149Simp drive_param.nr_sectors = SWAP_LONG (drive_param.u.driveid.lba_capacity); 357194149Simp 358194149Simp} 359194149Simp 360194149Simp 361194149Simp/* ------------------------------------------------------------------- * 362194149Simp * cf_send_cmd() * 363194149Simp * ------------------------------------------------------------------- * 364194149Simp * 365194149Simp * Send command to read/write one sector specified by lba. 366194149Simp * 367194149Simp */ 368194149Simpstatic void cf_send_cmd (uint32_t lba, uint8_t cmd) 369194149Simp{ 370194149Simp uint8_t status; 371194149Simp 372194149Simp if (bus_width == 8) { 373194149Simp volatile uint8_t *task_file; 374194149Simp 375194149Simp task_file = (volatile uint8_t *) base_addr; 376194149Simp 377194149Simp while ( (status = task_file[TF_STATUS]) & STATUS_BSY) { 378194149Simp DELAY(WAIT_DELAY); 379194149Simp } 380194149Simp 381194149Simp task_file[TF_SECTOR_COUNT] = 1; 382194149Simp task_file[TF_SECTOR_NUMBER] = (lba & 0xff); 383194149Simp task_file[TF_CYL_LSB] = ((lba >> 8) & 0xff); 384194149Simp task_file[TF_CYL_MSB] = ((lba >> 16) & 0xff); 385194149Simp task_file[TF_DRV_HEAD] = ((lba >> 24) & 0xff) | 0xe0; 386194149Simp task_file[TF_COMMAND] = cmd; 387194149Simp 388194149Simp } else { 389194149Simp volatile uint16_t *task_file; 390194149Simp 391194149Simp task_file = (volatile uint16_t *) base_addr; 392194149Simp 393194149Simp while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) { 394194149Simp DELAY(WAIT_DELAY); 395194149Simp } 396194149Simp 397194149Simp task_file[TF_SECTOR_COUNT/2] = 1 | ((lba & 0xff) << 8); 398194149Simp task_file[TF_CYL_LSB/2] = ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8); 399194149Simp task_file[TF_DRV_HEAD/2] = (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8); 400194149Simp 401194149Simp } 402194149Simp 403194149Simp cf_wait_busy(); 404194149Simp} 405194149Simp 406194149Simp/* ------------------------------------------------------------------- * 407194149Simp * cf_wait_busy() * 408194149Simp * ------------------------------------------------------------------- * 409194149Simp * 410194149Simp * Wait until the drive finishes a given command and data is 411194149Simp * ready to be transferred. This is done by repeatedly checking 412194149Simp * the BSY and DRQ bits of the status register. When the controller 413194149Simp * is ready for data transfer, it clears the BSY bit and sets the 414194149Simp * DRQ bit. 415194149Simp * 416194149Simp */ 417194149Simpstatic void cf_wait_busy (void) 418194149Simp{ 419194149Simp uint8_t status; 420194149Simp 421194149Simp//#define OCTEON_VISUAL_CF_2 1 422194149Simp#ifdef OCTEON_VISUAL_CF_2 423194149Simp static int where0 = 0; 424194149Simp 425194149Simp octeon_led_run_wheel(&where0, 2); 426194149Simp#endif 427194149Simp 428194149Simp if (bus_width == 8) { 429194149Simp volatile uint8_t *task_file; 430194149Simp task_file = (volatile uint8_t *)base_addr; 431194149Simp 432194149Simp status = task_file[TF_STATUS]; 433194149Simp while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { 434194149Simp DELAY(WAIT_DELAY); 435194149Simp status = task_file[TF_STATUS]; 436194149Simp } 437194149Simp } else { 438194149Simp volatile uint16_t *task_file; 439194149Simp task_file = (volatile uint16_t *)base_addr; 440194149Simp 441194149Simp status = task_file[TF_STATUS/2]>>8; 442194149Simp while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { 443194149Simp DELAY(WAIT_DELAY); 444194149Simp status = (uint8_t)(task_file[TF_STATUS/2]>>8); 445194149Simp } 446194149Simp } 447194149Simp 448194149Simp#ifdef OCTEON_VISUAL_CF_2 449194149Simp octeon_led_write_char(2, ' '); 450194149Simp#endif 451194149Simp} 452194149Simp 453194149Simp/* ------------------------------------------------------------------- * 454194149Simp * cf_swap_ascii() * 455194149Simp * ------------------------------------------------------------------- * 456194149Simp * 457194149Simp * The ascii string returned by the controller specifying 458194149Simp * the model of the drive is byte-swaped. This routine 459194149Simp * corrects the byte ordering. 460194149Simp * 461194149Simp */ 462194149Simpstatic void cf_swap_ascii (unsigned char str1[], char str2[]) 463194149Simp{ 464194149Simp int i; 465194149Simp 466194149Simp for(i = 0; i < MODEL_STR_SIZE; i++) { 467194149Simp str2[i] = str1[i^1]; 468194149Simp } 469194149Simp} 470194149Simp 471194149Simp 472194149Simp/* ------------------------------------------------------------------- * 473194149Simp * cf_probe() * 474194149Simp * ------------------------------------------------------------------- */ 475194149Simp 476194149Simpstatic int cf_probe (device_t dev) 477194149Simp{ 478194149Simp if (!octeon_board_real()) return 1; 479194149Simp 480194149Simp if (device_get_unit(dev) != 0) { 481194149Simp panic("can't attach more devices\n"); 482194149Simp } 483194149Simp 484194149Simp device_set_desc(dev, "Octeon Compact Flash Driver"); 485194149Simp 486194149Simp cf_cmd_identify(); 487194149Simp 488194149Simp return (0); 489194149Simp} 490194149Simp 491194149Simp/* ------------------------------------------------------------------- * 492194149Simp * cf_identify() * 493194149Simp * ------------------------------------------------------------------- * 494194149Simp * 495194149Simp * Find the bootbus region for the CF to determine 496194149Simp * 16 or 8 bit and check to see if device is 497194149Simp * inserted. 498194149Simp * 499194149Simp */ 500194149Simpstatic void cf_identify (driver_t *drv, device_t parent) 501194149Simp{ 502194149Simp uint8_t status; 503194149Simp int bus_region; 504194149Simp int count = 0; 505194149Simp octeon_mio_boot_reg_cfgx_t cfg; 506194149Simp 507194149Simp 508194149Simp if (!octeon_board_real()) return 1; 509194149Simp 510194149Simp base_addr = (void *) OCTEON_PHYS2PTR(OCTEON_CF_COMMON_BASE_ADDR); 511194149Simp 512194149Simp for (bus_region = 0; bus_region < 8; bus_region++) 513194149Simp { 514194149Simp cfg.word64 = oct_read64(OCTEON_MIO_BOOT_REG_CFGX(bus_region)); 515194149Simp if (cfg.bits.base == OCTEON_CF_COMMON_BASE_ADDR >> 16) 516194149Simp { 517194149Simp bus_width = (cfg.bits.width) ? 16: 8; 518194149Simp printf("Compact flash found in bootbus region %d (%d bit).\n", bus_region, bus_width); 519194149Simp break; 520194149Simp } 521194149Simp } 522194149Simp 523194149Simp if (bus_width == 8) { 524194149Simp volatile uint8_t *task_file; 525194149Simp task_file = (volatile uint8_t *) base_addr; 526194149Simp /* Check if CF is inserted */ 527194149Simp while ( (status = task_file[TF_STATUS]) & STATUS_BSY){ 528194149Simp if ((count++) == NR_TRIES ) { 529194149Simp printf("Compact Flash not present\n"); 530194149Simp return; 531194149Simp } 532194149Simp DELAY(WAIT_DELAY); 533194149Simp } 534194149Simp } else { 535194149Simp volatile uint16_t *task_file; 536194149Simp task_file = (volatile uint16_t *) base_addr; 537194149Simp /* Check if CF is inserted */ 538194149Simp while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY){ 539194149Simp if ((count++) == NR_TRIES ) { 540194149Simp printf("Compact Flash not present\n"); 541194149Simp return; 542194149Simp } 543194149Simp DELAY(WAIT_DELAY); 544194149Simp } 545194149Simp } 546194149Simp 547194149Simp BUS_ADD_CHILD(parent, 0, "cf", 0); 548194149Simp} 549194149Simp 550194149Simp 551194149Simp/* ------------------------------------------------------------------- * 552194149Simp * cf_attach_geom() * 553194149Simp * ------------------------------------------------------------------- */ 554194149Simp 555194149Simpstatic int cf_attach_geom (void *arg, int flag) 556194149Simp{ 557194149Simp struct cf_priv *cf_priv; 558194149Simp 559194149Simp cf_priv = (struct cf_priv *) arg; 560194149Simp cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev)); 561194149Simp cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name); 562194149Simp cf_priv->cf_geom->softc = cf_priv; 563194149Simp g_error_provider(cf_priv->cf_provider, 0); 564194149Simp 565194149Simp return (0); 566194149Simp} 567194149Simp 568194149Simp/* ------------------------------------------------------------------- * 569194149Simp * cf_attach_geom() * 570194149Simp * ------------------------------------------------------------------- */ 571194149Simpstatic void cf_attach_geom_proxy (void *arg, int flag) 572194149Simp{ 573194149Simp cf_attach_geom(arg, flag); 574194149Simp} 575194149Simp 576194149Simp 577194149Simp 578194149Simp/* ------------------------------------------------------------------- * 579194149Simp * cf_attach() * 580194149Simp * ------------------------------------------------------------------- */ 581194149Simp 582194149Simpstatic int cf_attach (device_t dev) 583194149Simp{ 584194149Simp struct cf_priv *cf_priv; 585194149Simp 586194149Simp if (!octeon_board_real()) return 1; 587194149Simp 588194149Simp cf_priv = device_get_softc(dev); 589194149Simp cf_priv->dev = dev; 590194149Simp cf_priv->drive_param = &drive_param; 591194149Simp 592194149Simp g_post_event(cf_attach_geom_proxy, cf_priv, M_WAITOK, NULL); 593194149Simp bioq_init(&cf_priv->cf_bq); 594194149Simp 595194149Simp return 0; 596194149Simp} 597194149Simp 598194149Simp 599194149Simpstatic device_method_t cf_methods[] = { 600194149Simp /* Device interface */ 601194149Simp DEVMETHOD(device_probe, cf_probe), 602194149Simp DEVMETHOD(device_identify, cf_identify), 603194149Simp DEVMETHOD(device_attach, cf_attach), 604194149Simp DEVMETHOD(device_detach, bus_generic_detach), 605194149Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 606194149Simp 607194149Simp { 0, 0 } 608194149Simp}; 609194149Simp 610194149Simpstatic driver_t cf_driver = { 611194149Simp "cf", 612194149Simp cf_methods, 613194149Simp sizeof(struct cf_priv) 614194149Simp}; 615194149Simp 616194149Simpstatic devclass_t cf_devclass; 617194149Simp 618194149SimpDRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0); 619194149Simp 620