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