summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/ata-disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata/ata-disk.c')
-rw-r--r--sys/dev/ata/ata-disk.c165
1 files changed, 117 insertions, 48 deletions
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index 1ed4c20..a4d7959 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org>
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h>
#include <sys/disk.h>
#include <sys/cons.h>
-#include <sys/sysctl.h>
#include <sys/sema.h>
#include <sys/taskqueue.h>
#include <vm/uma.h>
@@ -54,10 +53,12 @@ __FBSDID("$FreeBSD$");
#include <ata_if.h>
/* prototypes */
-static void ad_init(device_t);
-static void ad_done(struct ata_request *);
+static void ad_init(device_t dev);
+static void ad_get_geometry(device_t dev);
+static void ad_set_geometry(device_t dev);
+static void ad_done(struct ata_request *request);
static void ad_describe(device_t dev);
-static int ad_version(u_int16_t);
+static int ad_version(u_int16_t version);
static disk_strategy_t ad_strategy;
static disk_ioctl_t ad_ioctl;
static dumper_t ad_dump;
@@ -93,8 +94,6 @@ ad_attach(device_t dev)
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
struct ad_softc *adp;
- u_int32_t lbasize;
- u_int64_t lbasize48;
/* check that we have a virgin disk to attach */
if (device_get_ivars(dev))
@@ -106,37 +105,12 @@ ad_attach(device_t dev)
}
device_set_ivars(dev, adp);
- if ((atadev->param.atavalid & ATA_FLAG_54_58) &&
- atadev->param.current_heads && atadev->param.current_sectors) {
- adp->heads = atadev->param.current_heads;
- adp->sectors = atadev->param.current_sectors;
- adp->total_secs = (u_int32_t)atadev->param.current_size_1 |
- ((u_int32_t)atadev->param.current_size_2 << 16);
- }
- else {
- adp->heads = atadev->param.heads;
- adp->sectors = atadev->param.sectors;
- adp->total_secs = atadev->param.cylinders * adp->heads * adp->sectors;
- }
- lbasize = (u_int32_t)atadev->param.lba_size_1 |
- ((u_int32_t)atadev->param.lba_size_2 << 16);
-
- /* does this device need oldstyle CHS addressing */
- if (!ad_version(atadev->param.version_major) || !lbasize)
- atadev->flags |= ATA_D_USE_CHS;
-
- /* use the 28bit LBA size if valid or bigger than the CHS mapping */
- if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize)
- adp->total_secs = lbasize;
+ /* get device geometry into internal structs */
+ ad_get_geometry(dev);
- /* use the 48bit LBA size if valid */
- lbasize48 = ((u_int64_t)atadev->param.lba_size48_1) |
- ((u_int64_t)atadev->param.lba_size48_2 << 16) |
- ((u_int64_t)atadev->param.lba_size48_3 << 32) |
- ((u_int64_t)atadev->param.lba_size48_4 << 48);
- if ((atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) &&
- lbasize48 > ATA_MAX_28BIT_LBA)
- adp->total_secs = lbasize48;
+ /* set the max size if configured */
+ if (ata_setmax)
+ ad_set_geometry(dev);
/* init device parameters */
ad_init(dev);
@@ -151,10 +125,7 @@ ad_attach(device_t dev)
adp->disk->d_dump = ad_dump;
adp->disk->d_name = "ad";
adp->disk->d_drv1 = dev;
- if (ch->dma)
- adp->disk->d_maxsize = ch->dma->max_iosize;
- else
- adp->disk->d_maxsize = DFLTPHYS;
+ adp->disk->d_maxsize = ch->dma.max_iosize;
adp->disk->d_sectorsize = DEV_BSIZE;
adp->disk->d_mediasize = DEV_BSIZE * (off_t)adp->total_secs;
adp->disk->d_fwsectors = adp->sectors;
@@ -249,7 +220,7 @@ ad_spindown(void *priv)
struct ata_device *atadev = device_get_softc(dev);
struct ata_request *request;
- if(atadev->spindown == 0)
+ if (!atadev->spindown)
return;
device_printf(dev, "Idle, spin down\n");
atadev->spindown_state = 1;
@@ -274,9 +245,9 @@ ad_strategy(struct bio *bp)
struct ata_device *atadev = device_get_softc(dev);
struct ata_request *request;
- if (atadev->spindown != 0)
+ if (atadev->spindown)
callout_reset(&atadev->spindown_timer, hz * atadev->spindown,
- ad_spindown, dev);
+ ad_spindown, dev);
if (!(request = ata_alloc_request())) {
device_printf(dev, "FAILURE - out of memory in start\n");
@@ -292,7 +263,8 @@ ad_strategy(struct bio *bp)
device_printf(dev, "request while spun down, starting.\n");
atadev->spindown_state = 0;
request->timeout = 31;
- } else {
+ }
+ else {
request->timeout = 5;
}
request->retries = 2;
@@ -426,7 +398,105 @@ ad_init(device_t dev)
atadev->max_iosize = DEV_BSIZE;
}
-void
+static void
+ad_get_geometry(device_t dev)
+{
+ struct ata_device *atadev = device_get_softc(dev);
+ struct ad_softc *adp = device_get_ivars(dev);
+ u_int64_t lbasize48;
+ u_int32_t lbasize;
+
+ if ((atadev->param.atavalid & ATA_FLAG_54_58) &&
+ atadev->param.current_heads && atadev->param.current_sectors) {
+ adp->heads = atadev->param.current_heads;
+ adp->sectors = atadev->param.current_sectors;
+ adp->total_secs = (u_int32_t)atadev->param.current_size_1 |
+ ((u_int32_t)atadev->param.current_size_2 << 16);
+ }
+ else {
+ adp->heads = atadev->param.heads;
+ adp->sectors = atadev->param.sectors;
+ adp->total_secs = atadev->param.cylinders * adp->heads * adp->sectors;
+ }
+ lbasize = (u_int32_t)atadev->param.lba_size_1 |
+ ((u_int32_t)atadev->param.lba_size_2 << 16);
+
+ /* does this device need oldstyle CHS addressing */
+ if (!ad_version(atadev->param.version_major) || !lbasize)
+ atadev->flags |= ATA_D_USE_CHS;
+
+ /* use the 28bit LBA size if valid or bigger than the CHS mapping */
+ if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize)
+ adp->total_secs = lbasize;
+
+ /* use the 48bit LBA size if valid */
+ lbasize48 = ((u_int64_t)atadev->param.lba_size48_1) |
+ ((u_int64_t)atadev->param.lba_size48_2 << 16) |
+ ((u_int64_t)atadev->param.lba_size48_3 << 32) |
+ ((u_int64_t)atadev->param.lba_size48_4 << 48);
+ if ((atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) &&
+ lbasize48 > ATA_MAX_28BIT_LBA)
+ adp->total_secs = lbasize48;
+}
+
+static void
+ad_set_geometry(device_t dev)
+{
+ struct ad_softc *adp = device_get_ivars(dev);
+ struct ata_request *request;
+
+ if (1 | bootverbose)
+ device_printf(dev, "ORG %ju sectors [%juC/%dH/%dS]\n", adp->total_secs,
+ adp->total_secs / (adp->heads * adp->sectors),
+ adp->heads, adp->sectors);
+
+ if (!(request = ata_alloc_request()))
+ return;
+
+ /* get the max native size the device supports */
+ request->dev = dev;
+ request->u.ata.command = ATA_READ_NATIVE_MAX_ADDRESS;
+ request->u.ata.lba = 0;
+ request->u.ata.count = 0;
+ request->u.ata.feature = 0;
+ request->flags = ATA_R_CONTROL | ATA_R_QUIET;
+ request->timeout = 5;
+ request->retries = 0;
+ ata_queue_request(request);
+ if (request->status & ATA_S_ERROR)
+ goto out;
+
+ if (1 | bootverbose)
+ device_printf(dev, "MAX %ju sectors\n", request->u.ata.lba + 1);
+
+ /* if original size equals max size nothing more todo */
+ if (adp->total_secs >= request->u.ata.lba)
+ goto out;
+
+ /* set the max native size to its max */
+ request->dev = dev;
+ request->u.ata.command = ATA_SET_MAX_ADDRESS;
+ request->u.ata.count = 1;
+ request->u.ata.feature = 0;
+ request->flags = ATA_R_CONTROL;
+ request->timeout = 5;
+ request->retries = 0;
+ ata_queue_request(request);
+ if (request->status & ATA_S_ERROR)
+ goto out;
+
+ /* refresh geometry from drive */
+ ata_getparam(device_get_softc(dev), 0);
+ ad_get_geometry(dev);
+ if (1 | bootverbose)
+ device_printf(dev, "NEW %ju sectors [%juC/%dH/%dS]\n", adp->total_secs,
+ adp->total_secs / (adp->heads * adp->sectors),
+ adp->heads, adp->sectors);
+out:
+ ata_free_request(request);
+}
+
+static void
ad_describe(device_t dev)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
@@ -458,8 +528,7 @@ ad_describe(device_t dev)
device_printf(dev, "%juMB <%s%s %.8s> at ata%d-%s %s%s\n",
adp->total_secs / (1048576 / DEV_BSIZE),
vendor, product, atadev->param.revision,
- device_get_unit(ch->dev),
- (atadev->unit == ATA_MASTER) ? "master" : "slave",
+ device_get_unit(ch->dev), ata_unit2str(atadev),
(adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
ata_mode2str(atadev->mode));
if (bootverbose) {
OpenPOWER on IntegriCloud