Date: Sat, 6 Mar 2010 05:49:15 +0000 (UTC) From: Juli Mallett <jmallett@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r204789 - head/sys/mips/cavium Message-ID: <201003060549.o265nFG7031813@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jmallett Date: Sat Mar 6 05:49:15 2010 New Revision: 204789 URL: http://svn.freebsd.org/changeset/base/204789 Log: Check for device faults and for failures to set DRQ when expected, rather than spinning forever. This fixes booting with CF ejected. NB: I've made the driver pretty chatty about errors in case there's hardware that operates differently to mine, so we can easily track down any issues. Reviewed by: imp Sponsored by: Packet Forensics Modified: head/sys/mips/cavium/octeon_ebt3000_cf.c Modified: head/sys/mips/cavium/octeon_ebt3000_cf.c ============================================================================== --- head/sys/mips/cavium/octeon_ebt3000_cf.c Sat Mar 6 05:45:49 2010 (r204788) +++ head/sys/mips/cavium/octeon_ebt3000_cf.c Sat Mar 6 05:49:15 2010 (r204789) @@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$"); /* Status Register */ #define STATUS_BSY 0x80 /* Drive is busy */ #define STATUS_RDY 0x40 /* Drive is ready */ +#define STATUS_DF 0x20 /* Device fault */ #define STATUS_DRQ 0x08 /* Data can be transferred */ /* Miscelaneous */ @@ -153,11 +154,11 @@ static int cf_attach(device_t); static int cf_attach_geom(void *, int); /* ATA methods */ -static void cf_cmd_identify(void); -static void cf_cmd_write(uint32_t, uint32_t, void *); -static void cf_cmd_read(uint32_t, uint32_t, void *); -static void cf_wait_busy(void); -static void cf_send_cmd(uint32_t, uint8_t); +static int cf_cmd_identify(void); +static int cf_cmd_write(uint32_t, uint32_t, void *); +static int cf_cmd_read(uint32_t, uint32_t, void *); +static int cf_wait_busy(void); +static int cf_send_cmd(uint32_t, uint8_t); static void cf_attach_geom_proxy(void *arg, int flag); /* Miscelenous */ @@ -183,6 +184,8 @@ static int cf_access (struct g_provider * ------------------------------------------------------------------- */ static void cf_start (struct bio *bp) { + int error; + /* * Handle actual I/O requests. The request is passed down through * the bio struct. @@ -200,12 +203,19 @@ static void cf_start (struct bio *bp) if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) { if (bp->bio_cmd & BIO_READ) { - cf_cmd_read(bp->bio_length / drive_param.sector_size, - bp->bio_offset / drive_param.sector_size, bp->bio_data); - + error = cf_cmd_read(bp->bio_length / drive_param.sector_size, + bp->bio_offset / drive_param.sector_size, bp->bio_data); } else if (bp->bio_cmd & BIO_WRITE) { - cf_cmd_write(bp->bio_length / drive_param.sector_size, - bp->bio_offset/drive_param.sector_size, bp->bio_data); + error = cf_cmd_write(bp->bio_length / drive_param.sector_size, + bp->bio_offset/drive_param.sector_size, bp->bio_data); + } else { + printf("%s: unrecognized bio_cmd %x.\n", __func__, bp->bio_cmd); + error = ENOTSUP; + } + + if (error != 0) { + g_io_deliver(bp, error); + return; } bp->bio_resid = 0; @@ -227,12 +237,13 @@ static int cf_ioctl (struct g_provider * * * Read nr_sectors from the device starting from start_sector. */ -static void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) +static int cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf) { unsigned long lba; uint32_t count; uint16_t *ptr_16; uint8_t *ptr_8; + int error; //#define OCTEON_VISUAL_CF_0 1 #ifdef OCTEON_VISUAL_CF_0 @@ -244,8 +255,11 @@ static void cf_cmd_read (uint32_t nr_sec while (nr_sectors--) { - - cf_send_cmd(lba, CMD_READ_SECTOR); + error = cf_send_cmd(lba, CMD_READ_SECTOR); + if (error != 0) { + printf("%s: cf_send_cmd(CMD_READ_SECTOR) failed: %d\n", __func__, error); + return (error); + } if (bus_width == 8) { volatile uint8_t *task_file = (volatile uint8_t*)base_addr; @@ -270,6 +284,7 @@ static void cf_cmd_read (uint32_t nr_sec #ifdef OCTEON_VISUAL_CF_0 octeon_led_write_char(0, ' '); #endif + return (0); } @@ -279,12 +294,13 @@ static void cf_cmd_read (uint32_t nr_sec * * Write nr_sectors to the device starting from start_sector. */ -static void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) +static int cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf) { uint32_t lba; uint32_t count; uint16_t *ptr_16; uint8_t *ptr_8; + int error; //#define OCTEON_VISUAL_CF_1 1 #ifdef OCTEON_VISUAL_CF_1 @@ -295,8 +311,11 @@ static void cf_cmd_write (uint32_t nr_se ptr_16 = (uint16_t*)buf; while (nr_sectors--) { - - cf_send_cmd(lba, CMD_WRITE_SECTOR); + error = cf_send_cmd(lba, CMD_WRITE_SECTOR); + if (error != 0) { + printf("%s: cf_send_cmd(CMD_WRITE_SECTOR) failed: %d\n", __func__, error); + return (error); + } if (bus_width == 8) { volatile uint8_t *task_file; @@ -324,6 +343,7 @@ static void cf_cmd_write (uint32_t nr_se #ifdef OCTEON_VISUAL_CF_1 octeon_led_write_char(1, ' '); #endif + return (0); } @@ -335,10 +355,11 @@ static void cf_cmd_write (uint32_t nr_se * it in the drive_param structure * */ -static void cf_cmd_identify (void) +static int cf_cmd_identify (void) { int count; uint8_t status; + int error; if (bus_width == 8) { volatile uint8_t *task_file; @@ -356,11 +377,11 @@ static void cf_cmd_identify (void) task_file[TF_DRV_HEAD] = 0; task_file[TF_COMMAND] = CMD_IDENTIFY; - cf_wait_busy(); - - for (count = 0; count < SECTOR_SIZE; count++) - drive_param.u.buf[count] = task_file[TF_DATA]; - + error = cf_wait_busy(); + if (error == 0) { + for (count = 0; count < SECTOR_SIZE; count++) + drive_param.u.buf[count] = task_file[TF_DATA]; + } } else { volatile uint16_t *task_file; @@ -374,17 +395,22 @@ static void cf_cmd_identify (void) task_file[TF_CYL_LSB/2] = 0; /* this includes TF_CYL_MSB */ task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */ - cf_wait_busy(); - - for (count = 0; count < SECTOR_SIZE; count+=2) { - uint16_t temp; - temp = task_file[TF_DATA]; - - /* endianess will be swapped below */ - drive_param.u.buf[count] = (temp & 0xff); - drive_param.u.buf[count+1] = (temp & 0xff00)>>8; + error = cf_wait_busy(); + if (error == 0) { + for (count = 0; count < SECTOR_SIZE; count+=2) { + uint16_t temp; + temp = task_file[TF_DATA]; + + /* endianess will be swapped below */ + drive_param.u.buf[count] = (temp & 0xff); + drive_param.u.buf[count+1] = (temp & 0xff00)>>8; + } } } + if (error != 0) { + printf("%s: identify failed: %d\n", __func__, error); + return (error); + } cf_swap_ascii(drive_param.u.driveid.model, drive_param.model); @@ -394,6 +420,7 @@ static void cf_cmd_identify (void) drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.cur_sectors); drive_param.nr_sectors = SWAP_LONG (drive_param.u.driveid.lba_capacity); + return (0); } @@ -404,7 +431,7 @@ static void cf_cmd_identify (void) * Send command to read/write one sector specified by lba. * */ -static void cf_send_cmd (uint32_t lba, uint8_t cmd) +static int cf_send_cmd (uint32_t lba, uint8_t cmd) { uint8_t status; @@ -439,7 +466,7 @@ static void cf_send_cmd (uint32_t lba, u } - cf_wait_busy(); + return (cf_wait_busy()); } /* ------------------------------------------------------------------- * @@ -448,12 +475,16 @@ static void cf_send_cmd (uint32_t lba, u * * Wait until the drive finishes a given command and data is * ready to be transferred. This is done by repeatedly checking - * the BSY and DRQ bits of the status register. When the controller - * is ready for data transfer, it clears the BSY bit and sets the - * DRQ bit. + * the BSY bit of the status register. When the controller is ready for + * data transfer, it clears the BSY bit and sets the DRQ bit. + * + * If the DF bit is ever set, we return error. * + * This code originally spun on DRQ. If that behavior turns out to be + * necessary, a flag can be added or this function can be called + * repeatedly as long as it is returning ENXIO. */ -static void cf_wait_busy (void) +static int cf_wait_busy (void) { uint8_t status; @@ -469,7 +500,11 @@ static void cf_wait_busy (void) task_file = (volatile uint8_t *)base_addr; status = task_file[TF_STATUS]; - while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { + while ((status & STATUS_BSY) == STATUS_BSY) { + if ((status & STATUS_DF) != 0) { + printf("%s: device fault (status=%x)\n", __func__, status); + return (EIO); + } DELAY(WAIT_DELAY); status = task_file[TF_STATUS]; } @@ -478,15 +513,24 @@ static void cf_wait_busy (void) task_file = (volatile uint16_t *)base_addr; status = task_file[TF_STATUS/2]>>8; - while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) { + while ((status & STATUS_BSY) == STATUS_BSY) { + if ((status & STATUS_DF) != 0) { + printf("%s: device fault (status=%x)\n", __func__, status); + return (EIO); + } DELAY(WAIT_DELAY); status = (uint8_t)(task_file[TF_STATUS/2]>>8); } } + if ((status & STATUS_DRQ) == 0) { + printf("%s: device not ready (status=%x)\n", __func__, status); + return (ENXIO); + } #ifdef OCTEON_VISUAL_CF_2 octeon_led_write_char(2, ' '); #endif + return (0); } /* ------------------------------------------------------------------- * @@ -522,9 +566,7 @@ static int cf_probe (device_t dev) device_set_desc(dev, "Octeon Compact Flash Driver"); - cf_cmd_identify(); - - return (0); + return (cf_cmd_identify()); } /* ------------------------------------------------------------------- * @@ -543,7 +585,6 @@ static void cf_identify (driver_t *drv, int count = 0; octeon_mio_boot_reg_cfgx_t cfg; - if (!octeon_board_real()) return;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201003060549.o265nFG7031813>