octeon_ebt3000_cf.c revision 214708
1203130Simp/***********************license start*************** 2203130Simp * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights 3203130Simp * reserved. 4203130Simp * 5203130Simp * 6203130Simp * Redistribution and use in source and binary forms, with or without 7203130Simp * modification, are permitted provided that the following conditions are 8203130Simp * met: 9203130Simp * 10203130Simp * * Redistributions of source code must retain the above copyright 11203130Simp * notice, this list of conditions and the following disclaimer. 12203130Simp * 13203130Simp * * Redistributions in binary form must reproduce the above 14203130Simp * copyright notice, this list of conditions and the following 15203130Simp * disclaimer in the documentation and/or other materials provided 16203130Simp * with the distribution. 17203130Simp * 18203130Simp * * Neither the name of Cavium Networks nor the names of 19203130Simp * its contributors may be used to endorse or promote products 20203130Simp * derived from this software without specific prior written 21203130Simp * permission. 22203130Simp * 23203130Simp * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24203130Simp * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25203130Simp * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26203130Simp * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27203130Simp * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28203130Simp * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29203130Simp * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30203130Simp * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31203130Simp * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32203130Simp * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33203130Simp * 34203130Simp * 35203130Simp * For any questions regarding licensing please contact marketing@caviumnetworks.com 36203130Simp * 37203130Simp ***********************license end**************************************/ 38203130Simp 39194149Simp/* 40194149Simp * octeon_ebt3000_cf.c 41194149Simp * 42194149Simp */ 43194149Simp 44194149Simp#include <sys/cdefs.h> 45194149Simp__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_ebt3000_cf.c 214708 2010-11-02 23:43:44Z jmallett $"); 46194149Simp 47194149Simp#include <sys/param.h> 48194149Simp#include <sys/bio.h> 49194149Simp#include <sys/systm.h> 50194149Simp#include <sys/sysctl.h> 51210311Sjmallett#include <sys/ata.h> 52194149Simp#include <sys/bus.h> 53194149Simp#include <sys/kernel.h> 54194149Simp#include <sys/module.h> 55194149Simp#include <sys/rman.h> 56194149Simp#include <sys/power.h> 57194149Simp#include <sys/smp.h> 58194149Simp#include <sys/time.h> 59194149Simp#include <sys/timetc.h> 60194149Simp#include <sys/malloc.h> 61194149Simp 62194149Simp#include <geom/geom.h> 63194149Simp 64194149Simp#include <machine/clock.h> 65194149Simp#include <machine/locore.h> 66194149Simp#include <machine/md_var.h> 67194149Simp#include <machine/cpuregs.h> 68194149Simp 69202063Simp#include <mips/cavium/octeon_pcmap_regs.h> 70194149Simp 71210311Sjmallett#include <contrib/octeon-sdk/cvmx.h> 72210311Sjmallett 73194149Simp/* ATA Commands */ 74194149Simp#define CMD_READ_SECTOR 0x20 75194149Simp#define CMD_WRITE_SECTOR 0x30 76194149Simp#define CMD_IDENTIFY 0xEC 77194149Simp 78194149Simp/* The ATA Task File */ 79194149Simp#define TF_DATA 0x00 80194149Simp#define TF_ERROR 0x01 81194149Simp#define TF_PRECOMP 0x01 82194149Simp#define TF_SECTOR_COUNT 0x02 83194149Simp#define TF_SECTOR_NUMBER 0x03 84194149Simp#define TF_CYL_LSB 0x04 85194149Simp#define TF_CYL_MSB 0x05 86194149Simp#define TF_DRV_HEAD 0x06 87194149Simp#define TF_STATUS 0x07 88194149Simp#define TF_COMMAND 0x07 89194149Simp 90194149Simp/* Status Register */ 91194149Simp#define STATUS_BSY 0x80 /* Drive is busy */ 92194149Simp#define STATUS_RDY 0x40 /* Drive is ready */ 93204789Sjmallett#define STATUS_DF 0x20 /* Device fault */ 94194149Simp#define STATUS_DRQ 0x08 /* Data can be transferred */ 95194149Simp 96194149Simp/* Miscelaneous */ 97194149Simp#define SECTOR_SIZE 512 98194149Simp#define WAIT_DELAY 1000 99194149Simp#define NR_TRIES 1000 100194149Simp#define SWAP_SHORT(x) ((x << 8) | (x >> 8)) 101194149Simp#define MODEL_STR_SIZE 40 102194149Simp 103210311Sjmallett/* XXX */ 104210311Sjmallettextern cvmx_bootinfo_t *octeon_bootinfo; 105194149Simp 106194149Simp/* Globals */ 107194149Simpint bus_width; 108194149Simpvoid *base_addr; 109194149Simp 110194149Simp/* Device softc */ 111194149Simpstruct cf_priv { 112194149Simp 113194149Simp device_t dev; 114194149Simp struct drive_param *drive_param; 115194149Simp 116194149Simp struct bio_queue_head cf_bq; 117194149Simp struct g_geom *cf_geom; 118194149Simp struct g_provider *cf_provider; 119194149Simp 120194149Simp}; 121194149Simp 122194149Simp/* Device parameters */ 123194149Simpstruct drive_param{ 124194149Simp union { 125194149Simp char buf[SECTOR_SIZE]; 126210311Sjmallett struct ata_params driveid; 127194149Simp } u; 128194149Simp 129194149Simp char model[MODEL_STR_SIZE]; 130194149Simp uint32_t nr_sectors; 131194149Simp uint16_t sector_size; 132194149Simp uint16_t heads; 133194149Simp uint16_t tracks; 134194149Simp uint16_t sec_track; 135194149Simp 136194149Simp} drive_param; 137194149Simp 138194149Simp/* GEOM class implementation */ 139194149Simpstatic g_access_t cf_access; 140194149Simpstatic g_start_t cf_start; 141194149Simpstatic g_ioctl_t cf_ioctl; 142194149Simp 143194149Simpstruct g_class g_cf_class = { 144194149Simp .name = "CF", 145194149Simp .version = G_VERSION, 146194149Simp .start = cf_start, 147194149Simp .access = cf_access, 148194149Simp .ioctl = cf_ioctl, 149194149Simp}; 150194149Simp 151214708SjmallettDECLARE_GEOM_CLASS(g_cf_class, g_cf); 152214708Sjmallett 153194149Simp/* Device methods */ 154194149Simpstatic int cf_probe(device_t); 155194149Simpstatic void cf_identify(driver_t *, device_t); 156194149Simpstatic int cf_attach(device_t); 157194149Simpstatic int cf_attach_geom(void *, int); 158194149Simp 159194149Simp/* ATA methods */ 160204789Sjmallettstatic int cf_cmd_identify(void); 161204789Sjmallettstatic int cf_cmd_write(uint32_t, uint32_t, void *); 162204789Sjmallettstatic int cf_cmd_read(uint32_t, uint32_t, void *); 163204789Sjmallettstatic int cf_wait_busy(void); 164204789Sjmallettstatic int cf_send_cmd(uint32_t, uint8_t); 165194149Simpstatic void cf_attach_geom_proxy(void *arg, int flag); 166194149Simp 167194149Simp/* Miscelenous */ 168194149Simpstatic void cf_swap_ascii(unsigned char[], char[]); 169194149Simp 170194149Simp 171194149Simp/* ------------------------------------------------------------------- * 172194149Simp * cf_access() * 173194149Simp * ------------------------------------------------------------------- */ 174194149Simpstatic int cf_access (struct g_provider *pp, int r, int w, int e) 175194149Simp{ 176194149Simp 177194149Simp pp->sectorsize = drive_param.sector_size; 178194149Simp pp->stripesize = drive_param.heads * drive_param.sec_track * drive_param.sector_size; 179194149Simp pp->mediasize = pp->stripesize * drive_param.tracks; 180194149Simp 181194149Simp return (0); 182194149Simp} 183194149Simp 184194149Simp 185194149Simp/* ------------------------------------------------------------------- * 186194149Simp * cf_start() * 187194149Simp * ------------------------------------------------------------------- */ 188194149Simpstatic void cf_start (struct bio *bp) 189194149Simp{ 190204789Sjmallett int error; 191204789Sjmallett 192194149Simp /* 193194149Simp * Handle actual I/O requests. The request is passed down through 194194149Simp * the bio struct. 195194149Simp */ 196194149Simp 197194149Simp if(bp->bio_cmd & BIO_GETATTR) { 198194149Simp if (g_handleattr_int(bp, "GEOM::fwsectors", drive_param.sec_track)) 199194149Simp return; 200194149Simp if (g_handleattr_int(bp, "GEOM::fwheads", drive_param.heads)) 201194149Simp return; 202194149Simp g_io_deliver(bp, ENOIOCTL); 203194149Simp return; 204194149Simp } 205194149Simp 206194149Simp if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { 207194149Simp 208194149Simp if (bp->bio_cmd & BIO_READ) { 209204789Sjmallett error = cf_cmd_read(bp->bio_length / drive_param.sector_size, 210204789Sjmallett bp->bio_offset / drive_param.sector_size, bp->bio_data); 211194149Simp } else if (bp->bio_cmd & BIO_WRITE) { 212204789Sjmallett error = cf_cmd_write(bp->bio_length / drive_param.sector_size, 213204789Sjmallett bp->bio_offset/drive_param.sector_size, bp->bio_data); 214204789Sjmallett } else { 215204789Sjmallett printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd); 216204789Sjmallett error = ENOTSUP; 217194149Simp } 218194149Simp 219204789Sjmallett if (error != 0) { 220204789Sjmallett g_io_deliver(bp, error); 221204789Sjmallett return; 222204789Sjmallett } 223204789Sjmallett 224194149Simp bp->bio_resid = 0; 225194149Simp bp->bio_completed = bp->bio_length; 226194149Simp g_io_deliver(bp, 0); 227194149Simp } 228194149Simp} 229194149Simp 230194149Simp 231194149Simpstatic int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 232194149Simp{ 233194149Simp return (0); 234194149Simp} 235194149Simp 236194149Simp 237194149Simp/* ------------------------------------------------------------------- * 238194149Simp * cf_cmd_read() * 239194149Simp * ------------------------------------------------------------------- * 240194149Simp * 241194149Simp * Read nr_sectors from the device starting from start_sector. 242194149Simp */ 243204789Sjmallettstatic int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) 244194149Simp{ 245194149Simp unsigned long lba; 246194149Simp uint32_t count; 247194149Simp uint16_t *ptr_16; 248194149Simp uint8_t *ptr_8; 249204789Sjmallett int error; 250194149Simp 251194149Simp//#define OCTEON_VISUAL_CF_0 1 252194149Simp#ifdef OCTEON_VISUAL_CF_0 253194149Simp octeon_led_write_char(0, 'R'); 254194149Simp#endif 255194149Simp ptr_8 = (uint8_t*)buf; 256194149Simp ptr_16 = (uint16_t*)buf; 257194149Simp lba = start_sector; 258194149Simp 259194149Simp 260194149Simp while (nr_sectors--) { 261204789Sjmallett error = cf_send_cmd(lba, CMD_READ_SECTOR); 262204789Sjmallett if (error != 0) { 263204789Sjmallett printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error); 264204789Sjmallett return (error); 265204789Sjmallett } 266194149Simp 267194149Simp if (bus_width == 8) { 268194149Simp volatile uint8_t *task_file = (volatile uint8_t*)base_addr; 269194149Simp volatile uint8_t dummy; 270194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 271194149Simp *ptr_8++ = task_file[TF_DATA]; 272194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS]; 273194149Simp } 274194149Simp } else { 275194149Simp volatile uint16_t *task_file = (volatile uint16_t*)base_addr; 276194149Simp volatile uint16_t dummy; 277194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 278194149Simp uint16_t temp; 279194149Simp temp = task_file[TF_DATA]; 280194149Simp *ptr_16++ = SWAP_SHORT(temp); 281194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2]; 282194149Simp } 283194149Simp } 284194149Simp 285194149Simp lba ++; 286194149Simp } 287194149Simp#ifdef OCTEON_VISUAL_CF_0 288194149Simp octeon_led_write_char(0, ' '); 289194149Simp#endif 290204789Sjmallett return (0); 291194149Simp} 292194149Simp 293194149Simp 294194149Simp/* ------------------------------------------------------------------- * 295194149Simp * cf_cmd_write() * 296194149Simp * ------------------------------------------------------------------- * 297194149Simp * 298194149Simp * Write nr_sectors to the device starting from start_sector. 299194149Simp */ 300204789Sjmallettstatic int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) 301194149Simp{ 302194149Simp uint32_t lba; 303194149Simp uint32_t count; 304194149Simp uint16_t *ptr_16; 305194149Simp uint8_t *ptr_8; 306204789Sjmallett int error; 307194149Simp 308194149Simp//#define OCTEON_VISUAL_CF_1 1 309194149Simp#ifdef OCTEON_VISUAL_CF_1 310194149Simp octeon_led_write_char(1, 'W'); 311194149Simp#endif 312194149Simp lba = start_sector; 313194149Simp ptr_8 = (uint8_t*)buf; 314194149Simp ptr_16 = (uint16_t*)buf; 315194149Simp 316194149Simp while (nr_sectors--) { 317204789Sjmallett error = cf_send_cmd(lba, CMD_WRITE_SECTOR); 318204789Sjmallett if (error != 0) { 319204789Sjmallett printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error); 320204789Sjmallett return (error); 321204789Sjmallett } 322194149Simp 323194149Simp if (bus_width == 8) { 324194149Simp volatile uint8_t *task_file; 325194149Simp volatile uint8_t dummy; 326194149Simp 327194149Simp task_file = (volatile uint8_t *) base_addr; 328194149Simp for (count = 0; count < SECTOR_SIZE; count++) { 329194149Simp task_file[TF_DATA] = *ptr_8++; 330194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS]; 331194149Simp } 332194149Simp } else { 333194149Simp volatile uint16_t *task_file; 334194149Simp volatile uint16_t dummy; 335194149Simp 336194149Simp task_file = (volatile uint16_t *) base_addr; 337194149Simp for (count = 0; count < SECTOR_SIZE; count+=2) { 338194149Simp uint16_t temp = *ptr_16++; 339194149Simp task_file[TF_DATA] = SWAP_SHORT(temp); 340194149Simp if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2]; 341194149Simp } 342194149Simp } 343194149Simp 344194149Simp lba ++; 345194149Simp } 346194149Simp#ifdef OCTEON_VISUAL_CF_1 347194149Simp octeon_led_write_char(1, ' '); 348194149Simp#endif 349204789Sjmallett return (0); 350194149Simp} 351194149Simp 352194149Simp 353194149Simp/* ------------------------------------------------------------------- * 354194149Simp * cf_cmd_identify() * 355194149Simp * ------------------------------------------------------------------- * 356194149Simp * 357194149Simp * Read parameters and other information from the drive and store 358194149Simp * it in the drive_param structure 359194149Simp * 360194149Simp */ 361204789Sjmallettstatic int cf_cmd_identify (void) 362194149Simp{ 363194149Simp int count; 364194149Simp uint8_t status; 365204789Sjmallett int error; 366194149Simp 367194149Simp if (bus_width == 8) { 368194149Simp volatile uint8_t *task_file; 369194149Simp 370194149Simp task_file = (volatile uint8_t *) base_addr; 371194149Simp 372194149Simp while ((status = task_file[TF_STATUS]) & STATUS_BSY) { 373194149Simp DELAY(WAIT_DELAY); 374194149Simp } 375194149Simp 376194149Simp task_file[TF_SECTOR_COUNT] = 0; 377194149Simp task_file[TF_SECTOR_NUMBER] = 0; 378194149Simp task_file[TF_CYL_LSB] = 0; 379194149Simp task_file[TF_CYL_MSB] = 0; 380194149Simp task_file[TF_DRV_HEAD] = 0; 381194149Simp task_file[TF_COMMAND] = CMD_IDENTIFY; 382194149Simp 383204789Sjmallett error = cf_wait_busy(); 384204789Sjmallett if (error == 0) { 385204789Sjmallett for (count = 0; count < SECTOR_SIZE; count++) 386204789Sjmallett drive_param.u.buf[count] = task_file[TF_DATA]; 387204789Sjmallett } 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] = 0; /* this includes TF_SECTOR_NUMBER */ 398194149Simp task_file[TF_CYL_LSB/2] = 0; /* this includes TF_CYL_MSB */ 399194149Simp task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */ 400194149Simp 401204789Sjmallett error = cf_wait_busy(); 402204789Sjmallett if (error == 0) { 403204789Sjmallett for (count = 0; count < SECTOR_SIZE; count+=2) { 404204789Sjmallett uint16_t temp; 405204789Sjmallett temp = task_file[TF_DATA]; 406204789Sjmallett 407204789Sjmallett /* endianess will be swapped below */ 408204789Sjmallett drive_param.u.buf[count] = (temp & 0xff); 409204789Sjmallett drive_param.u.buf[count+1] = (temp & 0xff00)>>8; 410204789Sjmallett } 411194149Simp } 412194149Simp } 413204789Sjmallett if (error != 0) { 414204789Sjmallett printf("%s: identify failed: %d\n", __func__, error); 415204789Sjmallett return (error); 416204789Sjmallett } 417194149Simp 418194149Simp cf_swap_ascii(drive_param.u.driveid.model, drive_param.model); 419194149Simp 420194149Simp drive_param.sector_size = 512; //= SWAP_SHORT (drive_param.u.driveid.sector_bytes); 421210311Sjmallett drive_param.heads = SWAP_SHORT (drive_param.u.driveid.current_heads); 422210311Sjmallett drive_param.tracks = SWAP_SHORT (drive_param.u.driveid.current_cylinders); 423210311Sjmallett drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.current_sectors); 424210311Sjmallett drive_param.nr_sectors = (uint32_t)SWAP_SHORT (drive_param.u.driveid.lba_size_1) | 425210311Sjmallett ((uint32_t)SWAP_SHORT (drive_param.u.driveid.lba_size_2)); 426194149Simp 427204789Sjmallett return (0); 428194149Simp} 429194149Simp 430194149Simp 431194149Simp/* ------------------------------------------------------------------- * 432194149Simp * cf_send_cmd() * 433194149Simp * ------------------------------------------------------------------- * 434194149Simp * 435194149Simp * Send command to read/write one sector specified by lba. 436194149Simp * 437194149Simp */ 438204789Sjmallettstatic int cf_send_cmd (uint32_t lba, uint8_t cmd) 439194149Simp{ 440194149Simp uint8_t status; 441194149Simp 442194149Simp if (bus_width == 8) { 443194149Simp volatile uint8_t *task_file; 444194149Simp 445194149Simp task_file = (volatile uint8_t *) base_addr; 446194149Simp 447194149Simp while ( (status = task_file[TF_STATUS]) & STATUS_BSY) { 448194149Simp DELAY(WAIT_DELAY); 449194149Simp } 450194149Simp 451194149Simp task_file[TF_SECTOR_COUNT] = 1; 452194149Simp task_file[TF_SECTOR_NUMBER] = (lba & 0xff); 453194149Simp task_file[TF_CYL_LSB] = ((lba >> 8) & 0xff); 454194149Simp task_file[TF_CYL_MSB] = ((lba >> 16) & 0xff); 455194149Simp task_file[TF_DRV_HEAD] = ((lba >> 24) & 0xff) | 0xe0; 456194149Simp task_file[TF_COMMAND] = cmd; 457194149Simp 458194149Simp } else { 459194149Simp volatile uint16_t *task_file; 460194149Simp 461194149Simp task_file = (volatile uint16_t *) base_addr; 462194149Simp 463194149Simp while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) { 464194149Simp DELAY(WAIT_DELAY); 465194149Simp } 466194149Simp 467194149Simp task_file[TF_SECTOR_COUNT/2] = 1 | ((lba & 0xff) << 8); 468194149Simp task_file[TF_CYL_LSB/2] = ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8); 469194149Simp task_file[TF_DRV_HEAD/2] = (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8); 470194149Simp 471194149Simp } 472194149Simp 473204789Sjmallett return (cf_wait_busy()); 474194149Simp} 475194149Simp 476194149Simp/* ------------------------------------------------------------------- * 477194149Simp * cf_wait_busy() * 478194149Simp * ------------------------------------------------------------------- * 479194149Simp * 480194149Simp * Wait until the drive finishes a given command and data is 481194149Simp * ready to be transferred. This is done by repeatedly checking 482204789Sjmallett * the BSY bit of the status register. When the controller is ready for 483204789Sjmallett * data transfer, it clears the BSY bit and sets the DRQ bit. 484194149Simp * 485204789Sjmallett * If the DF bit is ever set, we return error. 486204789Sjmallett * 487204789Sjmallett * This code originally spun on DRQ. If that behavior turns out to be 488204789Sjmallett * necessary, a flag can be added or this function can be called 489204789Sjmallett * repeatedly as long as it is returning ENXIO. 490194149Simp */ 491204789Sjmallettstatic int cf_wait_busy (void) 492194149Simp{ 493194149Simp uint8_t status; 494194149Simp 495194149Simp//#define OCTEON_VISUAL_CF_2 1 496194149Simp#ifdef OCTEON_VISUAL_CF_2 497194149Simp static int where0 = 0; 498194149Simp 499194149Simp octeon_led_run_wheel(&where0, 2); 500194149Simp#endif 501194149Simp 502194149Simp if (bus_width == 8) { 503194149Simp volatile uint8_t *task_file; 504194149Simp task_file = (volatile uint8_t *)base_addr; 505194149Simp 506194149Simp status = task_file[TF_STATUS]; 507204789Sjmallett while ((status & STATUS_BSY) == STATUS_BSY) { 508204789Sjmallett if ((status & STATUS_DF) != 0) { 509204789Sjmallett printf("%s: device fault (status=%x)\n", __func__, status); 510204789Sjmallett return (EIO); 511204789Sjmallett } 512194149Simp DELAY(WAIT_DELAY); 513194149Simp status = task_file[TF_STATUS]; 514194149Simp } 515194149Simp } else { 516194149Simp volatile uint16_t *task_file; 517194149Simp task_file = (volatile uint16_t *)base_addr; 518194149Simp 519194149Simp status = task_file[TF_STATUS/2]>>8; 520204789Sjmallett while ((status & STATUS_BSY) == STATUS_BSY) { 521204789Sjmallett if ((status & STATUS_DF) != 0) { 522204789Sjmallett printf("%s: device fault (status=%x)\n", __func__, status); 523204789Sjmallett return (EIO); 524204789Sjmallett } 525194149Simp DELAY(WAIT_DELAY); 526194149Simp status = (uint8_t)(task_file[TF_STATUS/2]>>8); 527194149Simp } 528194149Simp } 529204789Sjmallett if ((status & STATUS_DRQ) == 0) { 530204789Sjmallett printf("%s: device not ready (status=%x)\n", __func__, status); 531204789Sjmallett return (ENXIO); 532204789Sjmallett } 533194149Simp 534194149Simp#ifdef OCTEON_VISUAL_CF_2 535194149Simp octeon_led_write_char(2, ' '); 536194149Simp#endif 537204789Sjmallett return (0); 538194149Simp} 539194149Simp 540194149Simp/* ------------------------------------------------------------------- * 541194149Simp * cf_swap_ascii() * 542194149Simp * ------------------------------------------------------------------- * 543194149Simp * 544194149Simp * The ascii string returned by the controller specifying 545194149Simp * the model of the drive is byte-swaped. This routine 546194149Simp * corrects the byte ordering. 547194149Simp * 548194149Simp */ 549194149Simpstatic void cf_swap_ascii (unsigned char str1[], char str2[]) 550194149Simp{ 551194149Simp int i; 552194149Simp 553194149Simp for(i = 0; i < MODEL_STR_SIZE; i++) { 554194149Simp str2[i] = str1[i^1]; 555194149Simp } 556194149Simp} 557194149Simp 558194149Simp 559194149Simp/* ------------------------------------------------------------------- * 560194149Simp * cf_probe() * 561194149Simp * ------------------------------------------------------------------- */ 562194149Simp 563194149Simpstatic int cf_probe (device_t dev) 564194149Simp{ 565210311Sjmallett if (octeon_is_simulation()) return 1; 566194149Simp 567194149Simp if (device_get_unit(dev) != 0) { 568194149Simp panic("can't attach more devices\n"); 569194149Simp } 570194149Simp 571194149Simp device_set_desc(dev, "Octeon Compact Flash Driver"); 572194149Simp 573204789Sjmallett return (cf_cmd_identify()); 574194149Simp} 575194149Simp 576194149Simp/* ------------------------------------------------------------------- * 577194149Simp * cf_identify() * 578194149Simp * ------------------------------------------------------------------- * 579194149Simp * 580194149Simp * Find the bootbus region for the CF to determine 581194149Simp * 16 or 8 bit and check to see if device is 582194149Simp * inserted. 583194149Simp * 584194149Simp */ 585194149Simpstatic void cf_identify (driver_t *drv, device_t parent) 586194149Simp{ 587194149Simp uint8_t status; 588194149Simp int bus_region; 589194149Simp int count = 0; 590210311Sjmallett cvmx_mio_boot_reg_cfgx_t cfg; 591194149Simp 592210311Sjmallett if (octeon_is_simulation()) 593194173Simp return; 594194149Simp 595210311Sjmallett base_addr = cvmx_phys_to_ptr(octeon_bootinfo->compact_flash_common_base_addr); 596194149Simp 597194149Simp for (bus_region = 0; bus_region < 8; bus_region++) 598194149Simp { 599210311Sjmallett cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(bus_region)); 600210311Sjmallett if (cfg.s.base == octeon_bootinfo->compact_flash_common_base_addr >> 16) 601194149Simp { 602210311Sjmallett bus_width = (cfg.s.width) ? 16: 8; 603194149Simp printf("Compact flash found in bootbus region %d (%d bit).\n", bus_region, bus_width); 604194149Simp break; 605194149Simp } 606194149Simp } 607194149Simp 608194149Simp if (bus_width == 8) { 609194149Simp volatile uint8_t *task_file; 610194149Simp task_file = (volatile uint8_t *) base_addr; 611194149Simp /* Check if CF is inserted */ 612194149Simp while ( (status = task_file[TF_STATUS]) & STATUS_BSY){ 613194149Simp if ((count++) == NR_TRIES ) { 614194149Simp printf("Compact Flash not present\n"); 615194149Simp return; 616194149Simp } 617194149Simp DELAY(WAIT_DELAY); 618194149Simp } 619194149Simp } else { 620194149Simp volatile uint16_t *task_file; 621194149Simp task_file = (volatile uint16_t *) base_addr; 622194149Simp /* Check if CF is inserted */ 623194149Simp while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY){ 624194149Simp if ((count++) == NR_TRIES ) { 625194149Simp printf("Compact Flash not present\n"); 626194149Simp return; 627194149Simp } 628194149Simp DELAY(WAIT_DELAY); 629194149Simp } 630194149Simp } 631194149Simp 632194149Simp BUS_ADD_CHILD(parent, 0, "cf", 0); 633194149Simp} 634194149Simp 635194149Simp 636194149Simp/* ------------------------------------------------------------------- * 637194149Simp * cf_attach_geom() * 638194149Simp * ------------------------------------------------------------------- */ 639194149Simp 640194149Simpstatic int cf_attach_geom (void *arg, int flag) 641194149Simp{ 642194149Simp struct cf_priv *cf_priv; 643194149Simp 644194149Simp cf_priv = (struct cf_priv *) arg; 645194149Simp cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev)); 646194149Simp cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name); 647194149Simp cf_priv->cf_geom->softc = cf_priv; 648194149Simp g_error_provider(cf_priv->cf_provider, 0); 649194149Simp 650194149Simp return (0); 651194149Simp} 652194149Simp 653194149Simp/* ------------------------------------------------------------------- * 654194149Simp * cf_attach_geom() * 655194149Simp * ------------------------------------------------------------------- */ 656194149Simpstatic void cf_attach_geom_proxy (void *arg, int flag) 657194149Simp{ 658194149Simp cf_attach_geom(arg, flag); 659194149Simp} 660194149Simp 661194149Simp 662194149Simp 663194149Simp/* ------------------------------------------------------------------- * 664194149Simp * cf_attach() * 665194149Simp * ------------------------------------------------------------------- */ 666194149Simp 667194149Simpstatic int cf_attach (device_t dev) 668194149Simp{ 669194149Simp struct cf_priv *cf_priv; 670194149Simp 671210311Sjmallett if (octeon_is_simulation()) return 1; 672194149Simp 673194149Simp cf_priv = device_get_softc(dev); 674194149Simp cf_priv->dev = dev; 675194149Simp cf_priv->drive_param = &drive_param; 676194149Simp 677194149Simp g_post_event(cf_attach_geom_proxy, cf_priv, M_WAITOK, NULL); 678194149Simp bioq_init(&cf_priv->cf_bq); 679194149Simp 680194149Simp return 0; 681194149Simp} 682194149Simp 683194149Simp 684194149Simpstatic device_method_t cf_methods[] = { 685194149Simp /* Device interface */ 686194149Simp DEVMETHOD(device_probe, cf_probe), 687194149Simp DEVMETHOD(device_identify, cf_identify), 688194149Simp DEVMETHOD(device_attach, cf_attach), 689194149Simp DEVMETHOD(device_detach, bus_generic_detach), 690194149Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 691194149Simp 692194149Simp { 0, 0 } 693194149Simp}; 694194149Simp 695194149Simpstatic driver_t cf_driver = { 696194149Simp "cf", 697194149Simp cf_methods, 698194149Simp sizeof(struct cf_priv) 699194149Simp}; 700194149Simp 701194149Simpstatic devclass_t cf_devclass; 702194149Simp 703194149SimpDRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0); 704194149Simp 705