This is the much rumoured ATA mkIII update that I've been working on.

o       ATA is now fully newbus'd and split into modules.
        This means that on a modern system you just load "atapci and ata"
        to get the base support, and then one or more of the device
        subdrivers "atadisk atapicd atapifd atapist ataraid".
        All can be loaded/unloaded anytime, but for obvious reasons you
        dont want to unload atadisk when you have mounted filesystems.

o       The device identify part of the probe has been rewritten to fix
        the problems with odd devices the old had, and to try to remove
        so of the long delays some HW could provoke. Also probing is done
	without the need for interrupts, making earlier probing possible.

o       SATA devices can be hot inserted/removed and devices will be created/
        removed in /dev accordingly.
	NOTE: only supported on controllers that has this feature:
	Promise and Silicon Image for now.
	On other controllers the usual atacontrol detach/attach dance is
	still needed.

o	Support for "atomic" composite ATA requests used for RAID.

o       ATA RAID support has been rewritten and and now supports these
        metadata formats:
                 "Adaptec HostRAID"
                 "Highpoint V2 RocketRAID"
                 "Highpoint V3 RocketRAID"
                 "Intel MatrixRAID"
                 "Integrated Technology Express"
                 "LSILogic V2 MegaRAID"
                 "LSILogic V3 MegaRAID"
                 "Promise FastTrak"
                 "Silicon Image Medley"
		 "FreeBSD PseudoRAID"

o       Update the ioctl API to match new RAID levels etc.

o       Update atacontrol to know about the new RAID levels etc
        NOTE: you need to recompile atacontrol with the new sys/ata.h,
        make world will take care of that.
	NOTE2: that rebuild is done differently from the old system as
	the rebuild is now done piggybacked on read requests to the
	array, so atacontrol simply starts a background "dd" to rebuild
	the array.

o       The reinit code has been worked over to be much more robust.

o       The timeout code has been overhauled for races.

o	Support of new chipsets.

o       Lots of fixes for bugs found while doing the modulerization and
        reviewing the old code.

Missing or changed features from current ATA:

o       atapi-cd no longer has support for ATAPI changers. Todays its
        much cheaper and alot faster to copy those CD images to disk
        and serve them from there. Besides they dont seem to be made
        anymore, maybe for that exact reason.

o       ATA RAID can only read metadata from all the above metadata formats,
	not write all of them (Promise and Highpoint V2 so far). This means
	that arrays can be picked up from the BIOS, but they cannot be
	created from FreeBSD. There is more to it than just the missing
	write metadata support, those formats are not unique to a given
	controller like Promise and Highpoint formats, instead they exist
	for several types, and even worse, some controllers can have
	different formats and its impossible to tell which one.
	The outcome is that we cannot reliably create the metadata of those
	formats and be sure the controller BIOS will understand it.
	However write support is needed to update/fail/rebuild the arrays
	properly so it sits fairly high on the TODO list.

o       So far atapicam is not supported with these changes. When/if this
	will change is up to the maintainer of atapi-cam so go there for
	questions.

HW donated by:  Webveveriet AS
HW donated by:  Frode Nordahl
HW donated by:  Yahoo!
HW donated by:  Sentex
Patience by:	Vife and my boys (and even the cats)
This commit is contained in:
Søren Schmidt 2005-03-30 12:03:40 +00:00
parent 4cb39345c0
commit 8ca4df3299
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=144330
41 changed files with 8697 additions and 6276 deletions

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 2000 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -373,17 +373,21 @@ main(int argc, char **argv)
iocmd.cmd = ATARAIDCREATE;
if (argc > 2) {
if (!strcmp(argv[2], "RAID0") ||
!strcmp(argv[2], "stripe"))
iocmd.u.raid_setup.type = 1;
if (!strcmp(argv[2], "RAID1") ||
!strcmp(argv[2],"mirror"))
iocmd.u.raid_setup.type = 2;
if (!strcmp(argv[2], "RAID0+1"))
iocmd.u.raid_setup.type = 3;
if (!strcmp(argv[2], "SPAN") ||
!strcmp(argv[2], "JBOD"))
iocmd.u.raid_setup.type = 4;
if (!strcasecmp(argv[2], "RAID0") ||
!strcasecmp(argv[2], "stripe"))
iocmd.u.raid_setup.type = AR_RAID0;
if (!strcasecmp(argv[2], "RAID1") ||
!strcasecmp(argv[2],"mirror"))
iocmd.u.raid_setup.type = AR_RAID1;
if (!strcasecmp(argv[2], "RAID0+1") ||
!strcasecmp(argv[2],"RAID10"))
iocmd.u.raid_setup.type = AR_RAID01;
if (!strcasecmp(argv[2], "RAID5"))
iocmd.u.raid_setup.type = AR_RAID5;
if (!strcasecmp(argv[2], "SPAN"))
iocmd.u.raid_setup.type = AR_SPAN;
if (!strcasecmp(argv[2], "JBOD"))
iocmd.u.raid_setup.type = AR_JBOD;
}
if (!iocmd.u.raid_setup.type) {
fprintf(stderr, "atacontrol: Invalid RAID type\n");
@ -393,7 +397,9 @@ main(int argc, char **argv)
exit(EX_USAGE);
}
if (iocmd.u.raid_setup.type & 1) {
if (iocmd.u.raid_setup.type == AR_RAID0 ||
iocmd.u.raid_setup.type == AR_RAID01 ||
iocmd.u.raid_setup.type == AR_RAID5) {
if (argc < 4 ||
!sscanf(argv[3], "%d",
&iocmd.u.raid_setup.interleave) == 1) {
@ -451,6 +457,14 @@ main(int argc, char **argv)
iocmd.cmd = ATARAIDREBUILD;
if (ioctl(fd, IOCATA, &iocmd) < 0)
warn("ioctl(ATARAIDREBUILD)");
else {
char buffer[128];
sprintf(buffer, "/usr/bin/nice -n 20 /bin/dd "
"if=/dev/ar%d of=/dev/null bs=1m &",
iocmd.channel);
if (system(buffer))
warn("background dd");
}
}
else if (!strcmp(argv[1], "status") && argc == 3) {
int i;
@ -467,10 +481,16 @@ main(int argc, char **argv)
case AR_RAID1:
printf("RAID1");
break;
case AR_RAID0 | AR_RAID1:
case AR_RAID01:
printf("RAID0+1 stripesize=%d",
iocmd.u.raid_status.interleave);
break;
case AR_RAID5:
printf("RAID5 stripesize=%d",
iocmd.u.raid_status.interleave);
break;
case AR_JBOD:
printf("JBOD");
case AR_SPAN:
printf("SPAN");
break;

View File

@ -387,6 +387,7 @@ dev/an/if_an_isa.c optional an isa
dev/an/if_an_pccard.c optional an pccard
dev/an/if_an_pci.c optional an pci
dev/asr/asr.c optional asr pci
dev/ata/ata_if.m optional ata
dev/ata/ata-all.c optional ata
dev/ata/ata-card.c optional ata pccard
dev/ata/ata-cbus.c optional ata pc98

View File

@ -298,8 +298,9 @@ ${_src}:
.endfor
.endif
MFILES?= dev/acpica/acpi_if.m dev/eisa/eisa_if.m dev/iicbus/iicbb_if.m \
dev/iicbus/iicbus_if.m dev/mii/miibus_if.m dev/ofw/ofw_bus_if.m \
MFILES?= dev/acpica/acpi_if.m dev/ata/ata_if.m dev/eisa/eisa_if.m \
dev/iicbus/iicbb_if.m dev/iicbus/iicbus_if.m \
dev/mii/miibus_if.m dev/ofw/ofw_bus_if.m \
dev/pccard/card_if.m dev/pccard/power_if.m dev/pci/pci_if.m \
dev/pci/pcib_if.m dev/ppbus/ppbus_if.m dev/smbus/smbus_if.m \
dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \

View File

@ -303,12 +303,6 @@ ISP_FW_CRASH_DUMP opt_isp.h
# Options used in the 'ata' ATA/ATAPI driver
ATA_STATIC_ID opt_ata.h
ATA_NOPCI opt_ata.h
DEV_ATADISK opt_ata.h
DEV_ATAPICD opt_ata.h
DEV_ATAPIST opt_ata.h
DEV_ATAPIFD opt_ata.h
DEV_ATAPICAM opt_ata.h
DEV_ATARAID opt_ata.h
# Net stuff.
ACCEPT_FILTER_DATA

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,220 +29,235 @@
*/
/* ATA register defines */
#define ATA_DATA 0x00 /* data register */
#define ATA_DATA 0x00 /* data register */
#define ATA_ERROR 0x01 /* (R) error register */
#define ATA_E_ILI 0x01 /* illegal length */
#define ATA_E_NM 0x02 /* no media */
#define ATA_E_ABORT 0x04 /* command aborted */
#define ATA_E_MCR 0x08 /* media change request */
#define ATA_E_IDNF 0x10 /* ID not found */
#define ATA_E_MC 0x20 /* media changed */
#define ATA_E_UNC 0x40 /* uncorrectable data */
#define ATA_E_ICRC 0x80 /* UDMA crc error */
#define ATA_E_MASK 0x0f /* error mask */
#define ATA_SK_MASK 0xf0 /* sense key mask */
#define ATA_SK_NO_SENSE 0x00 /* no specific sense key info */
#define ATA_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */
#define ATA_SK_NOT_READY 0x20 /* no access to drive */
#define ATA_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */
#define ATA_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */
#define ATA_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */
#define ATA_SK_UNIT_ATTENTION 0x60 /* media changed */
#define ATA_SK_DATA_PROTECT 0x70 /* write protect */
#define ATA_SK_BLANK_CHECK 0x80 /* blank check */
#define ATA_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */
#define ATA_SK_COPY_ABORTED 0xa0 /* copy aborted */
#define ATA_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */
#define ATA_SK_EQUAL 0xc0 /* equal */
#define ATA_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */
#define ATA_SK_MISCOMPARE 0xe0 /* data dont match the medium */
#define ATA_SK_RESERVED 0xf0
#define ATA_ERROR 0x01 /* (R) error register */
#define ATA_E_ILI 0x01 /* illegal length */
#define ATA_E_NM 0x02 /* no media */
#define ATA_E_ABORT 0x04 /* command aborted */
#define ATA_E_MCR 0x08 /* media change request */
#define ATA_E_IDNF 0x10 /* ID not found */
#define ATA_E_MC 0x20 /* media changed */
#define ATA_E_UNC 0x40 /* uncorrectable data */
#define ATA_E_ICRC 0x80 /* UDMA crc error */
#define ATA_E_MASK 0x0f /* error mask */
#define ATA_SK_MASK 0xf0 /* sense key mask */
#define ATA_SK_NO_SENSE 0x00 /* no specific sense key info */
#define ATA_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */
#define ATA_SK_NOT_READY 0x20 /* no access to drive */
#define ATA_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */
#define ATA_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */
#define ATA_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */
#define ATA_SK_UNIT_ATTENTION 0x60 /* media changed */
#define ATA_SK_DATA_PROTECT 0x70 /* write protect */
#define ATA_SK_BLANK_CHECK 0x80 /* blank check */
#define ATA_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */
#define ATA_SK_COPY_ABORTED 0xa0 /* copy aborted */
#define ATA_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */
#define ATA_SK_EQUAL 0xc0 /* equal */
#define ATA_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */
#define ATA_SK_MISCOMPARE 0xe0 /* data dont match the medium */
#define ATA_SK_RESERVED 0xf0
#define ATA_FEATURE 0x01 /* (W) feature register */
#define ATA_F_DMA 0x01 /* enable DMA */
#define ATA_F_OVL 0x02 /* enable overlap */
#define ATA_FEATURE 0x01 /* (W) feature register */
#define ATA_F_DMA 0x01 /* enable DMA */
#define ATA_F_OVL 0x02 /* enable overlap */
#define ATA_COUNT 0x02 /* (W) sector count */
#define ATA_IREASON 0x02 /* (R) interrupt reason */
#define ATA_I_CMD 0x01 /* cmd (1) | data (0) */
#define ATA_I_IN 0x02 /* read (1) | write (0) */
#define ATA_I_RELEASE 0x04 /* released bus (1) */
#define ATA_I_TAGMASK 0xf8 /* tag mask */
#define ATA_COUNT 0x02 /* (W) sector count */
#define ATA_IREASON 0x02 /* (R) interrupt reason */
#define ATA_I_CMD 0x01 /* cmd (1) | data (0) */
#define ATA_I_IN 0x02 /* read (1) | write (0) */
#define ATA_I_RELEASE 0x04 /* released bus (1) */
#define ATA_I_TAGMASK 0xf8 /* tag mask */
#define ATA_SECTOR 0x03 /* sector # */
#define ATA_CYL_LSB 0x04 /* cylinder# LSB */
#define ATA_CYL_MSB 0x05 /* cylinder# MSB */
#define ATA_DRIVE 0x06 /* Sector/Drive/Head register */
#define ATA_D_LBA 0x40 /* use LBA addressing */
#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */
#define ATA_SECTOR 0x03 /* sector # */
#define ATA_CYL_LSB 0x04 /* cylinder# LSB */
#define ATA_CYL_MSB 0x05 /* cylinder# MSB */
#define ATA_DRIVE 0x06 /* Sector/Drive/Head register */
#define ATA_D_LBA 0x40 /* use LBA addressing */
#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */
#define ATA_CMD 0x07 /* command register */
#define ATA_CMD 0x07 /* command register */
#define ATA_STATUS 0x07 /* status register */
#define ATA_S_ERROR 0x01 /* error */
#define ATA_S_INDEX 0x02 /* index */
#define ATA_S_CORR 0x04 /* data corrected */
#define ATA_S_DRQ 0x08 /* data request */
#define ATA_S_DSC 0x10 /* drive seek completed */
#define ATA_S_SERVICE 0x10 /* drive needs service */
#define ATA_S_DWF 0x20 /* drive write fault */
#define ATA_S_DMA 0x20 /* DMA ready */
#define ATA_S_READY 0x40 /* drive ready */
#define ATA_S_BUSY 0x80 /* busy */
#define ATA_STATUS 0x07 /* status register */
#define ATA_S_ERROR 0x01 /* error */
#define ATA_S_INDEX 0x02 /* index */
#define ATA_S_CORR 0x04 /* data corrected */
#define ATA_S_DRQ 0x08 /* data request */
#define ATA_S_DSC 0x10 /* drive seek completed */
#define ATA_S_SERVICE 0x10 /* drive needs service */
#define ATA_S_DWF 0x20 /* drive write fault */
#define ATA_S_DMA 0x20 /* DMA ready */
#define ATA_S_READY 0x40 /* drive ready */
#define ATA_S_BUSY 0x80 /* busy */
#define ATA_ALTSTAT 0x08 /* alternate status register */
#define ATA_ALTOFFSET 0x206 /* alternate registers offset */
#define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */
#define ATA_PC98_ALTOFFSET 0x10c /* do for PC98 devices */
#define ATA_A_IDS 0x02 /* disable interrupts */
#define ATA_A_RESET 0x04 /* RESET controller */
#define ATA_A_4BIT 0x08 /* 4 head bits */
#define ATA_ALTSTAT 0x08 /* alternate status register */
#define ATA_ALTOFFSET 0x206 /* alternate registers offset */
#define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */
#define ATA_PC98_ALTOFFSET 0x10c /* do for PC98 devices */
#define ATA_A_IDS 0x02 /* disable interrupts */
#define ATA_A_RESET 0x04 /* RESET controller */
#define ATA_A_4BIT 0x08 /* 4 head bits */
#define ATA_A_HOB 0x80 /* High Order Byte enable */
/* ATAPI misc defines */
#define ATAPI_MAGIC_LSB 0x14
#define ATAPI_MAGIC_MSB 0xeb
#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN)
#define ATAPI_P_WRITE (ATA_S_DRQ)
#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD)
#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN)
#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN)
#define ATAPI_P_ABORT 0
#define ATAPI_MAGIC_LSB 0x14
#define ATAPI_MAGIC_MSB 0xeb
#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN)
#define ATAPI_P_WRITE (ATA_S_DRQ)
#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD)
#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN)
#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN)
#define ATAPI_P_ABORT 0
/* misc defines */
#define ATA_PRIMARY 0x1f0
#define ATA_SECONDARY 0x170
#define ATA_PC98_BANK 0x432
#define ATA_IOSIZE 0x08
#define ATA_PC98_IOSIZE 0x10
#define ATA_ALTIOSIZE 0x01
#define ATA_BMIOSIZE 0x08
#define ATA_PC98_BANKIOSIZE 0x01
#define ATA_IOADDR_RID 0
#define ATA_ALTADDR_RID 1
#define ATA_BMADDR_RID 0x20
#define ATA_PC98_ALTADDR_RID 8
#define ATA_PC98_BANKADDR_RID 9
#define ATA_PRIMARY 0x1f0
#define ATA_SECONDARY 0x170
#define ATA_PC98_BANK 0x432
#define ATA_IOSIZE 0x08
#define ATA_PC98_IOSIZE 0x10
#define ATA_ALTIOSIZE 0x01
#define ATA_BMIOSIZE 0x08
#define ATA_PC98_BANKIOSIZE 0x01
#define ATA_IOADDR_RID 0
#define ATA_ALTADDR_RID 1
#define ATA_BMADDR_RID 0x20
#define ATA_PC98_ALTADDR_RID 8
#define ATA_PC98_BANKADDR_RID 9
#define ATA_IRQ_RID 0
#define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1)
#define ATA_IRQ_RID 0
#define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1)
/* busmaster DMA related defines */
#define ATA_DMA_ENTRIES 256
#define ATA_DMA_EOT 0x80000000
#define ATA_DMA_ENTRIES 256
#define ATA_DMA_EOT 0x80000000
#define ATA_BMCMD_PORT 0x09
#define ATA_BMCMD_START_STOP 0x01
#define ATA_BMCMD_WRITE_READ 0x08
#define ATA_BMCMD_PORT 0x09
#define ATA_BMCMD_START_STOP 0x01
#define ATA_BMCMD_WRITE_READ 0x08
#define ATA_BMDEVSPEC_0 0x0a
#define ATA_BMSTAT_PORT 0x0b
#define ATA_BMSTAT_ACTIVE 0x01
#define ATA_BMSTAT_ERROR 0x02
#define ATA_BMSTAT_INTERRUPT 0x04
#define ATA_BMSTAT_MASK 0x07
#define ATA_BMSTAT_DMA_MASTER 0x20
#define ATA_BMSTAT_DMA_SLAVE 0x40
#define ATA_BMSTAT_DMA_SIMPLEX 0x80
#define ATA_BMDEVSPEC_0 0x0a
#define ATA_BMSTAT_PORT 0x0b
#define ATA_BMSTAT_ACTIVE 0x01
#define ATA_BMSTAT_ERROR 0x02
#define ATA_BMSTAT_INTERRUPT 0x04
#define ATA_BMSTAT_MASK 0x07
#define ATA_BMSTAT_DMA_MASTER 0x20
#define ATA_BMSTAT_DMA_SLAVE 0x40
#define ATA_BMSTAT_DMA_SIMPLEX 0x80
#define ATA_BMDEVSPEC_1 0x0c
#define ATA_BMDTP_PORT 0x0d
#define ATA_BMDEVSPEC_1 0x0c
#define ATA_BMDTP_PORT 0x0d
#define ATA_IDX_ADDR 0x0e
#define ATA_IDX_DATA 0x0f
#define ATA_MAX_RES 0x10
#define ATA_IDX_ADDR 0x0e
#define ATA_IDX_DATA 0x0f
#define ATA_MAX_RES 0x10
#define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY)
#define ATA_OP_CONTINUES 0
#define ATA_OP_FINISHED 1
#define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY)
#define ATA_OP_CONTINUES 0
#define ATA_OP_FINISHED 1
#define ATA_MAX_28BIT_LBA 268435455
#define ATA_MAX_28BIT_LBA 268435455
/* ATAPI request sense structure */
struct atapi_sense {
u_int8_t error_code :7; /* current or deferred errors */
u_int8_t valid :1; /* follows ATAPI spec */
u_int8_t segment; /* Segment number */
u_int8_t sense_key :4; /* sense key */
u_int8_t reserved2_4 :1; /* reserved */
u_int8_t ili :1; /* incorrect length indicator */
u_int8_t eom :1; /* end of medium */
u_int8_t filemark :1; /* filemark */
u_int32_t cmd_info __packed; /* cmd information */
u_int8_t sense_length; /* additional sense len (n-7) */
u_int32_t cmd_specific_info __packed; /* additional cmd spec info */
u_int8_t asc; /* additional sense code */
u_int8_t ascq; /* additional sense code qual */
u_int8_t replaceable_unit_code; /* replaceable unit code */
u_int8_t sk_specific :7; /* sense key specific */
u_int8_t sksv :1; /* sense key specific info OK */
u_int8_t sk_specific1; /* sense key specific */
u_int8_t sk_specific2; /* sense key specific */
u_int8_t error_code :7; /* current or deferred errors */
u_int8_t valid :1; /* follows ATAPI spec */
u_int8_t segment; /* Segment number */
u_int8_t sense_key :4; /* sense key */
u_int8_t reserved2_4 :1; /* reserved */
u_int8_t ili :1; /* incorrect length indicator */
u_int8_t eom :1; /* end of medium */
u_int8_t filemark :1; /* filemark */
u_int32_t cmd_info __packed; /* cmd information */
u_int8_t sense_length; /* additional sense len (n-7) */
u_int32_t cmd_specific_info __packed; /* additional cmd spec info */
u_int8_t asc; /* additional sense code */
u_int8_t ascq; /* additional sense code qual */
u_int8_t replaceable_unit_code; /* replaceable unit code */
u_int8_t sk_specific :7; /* sense key specific */
u_int8_t sksv :1; /* sense key specific info OK */
u_int8_t sk_specific1; /* sense key specific */
u_int8_t sk_specific2; /* sense key specific */
};
struct ata_request {
struct ata_device *device; /* ptr to device softc */
void *driver; /* driver specific */
/* structure used for composite atomic operations */
struct ata_composite {
struct mtx lock; /* control lock */
u_int32_t rd_needed; /* needed read subdisks */
u_int32_t rd_done; /* done read subdisks */
u_int32_t wr_needed; /* needed write subdisks */
u_int32_t wr_depend; /* write depends on subdisks */
u_int32_t wr_done; /* done write subdisks */
struct ata_request *request[32]; /* size must match maps above */
caddr_t data_1;
caddr_t data_2;
};
/* structure used to queue an ATA/ATAPI request */
struct ata_request {
device_t dev; /* device handle */
union {
struct {
u_int8_t command; /* command reg */
u_int8_t feature; /* feature reg */
u_int16_t count; /* count reg */
u_int64_t lba; /* lba reg */
u_int8_t command; /* command reg */
u_int8_t feature; /* feature reg */
u_int16_t count; /* count reg */
u_int64_t lba; /* lba reg */
} ata;
struct {
u_int8_t ccb[16]; /* ATAPI command block */
struct atapi_sense sense_data; /* ATAPI request sense data */
u_int8_t sense_key; /* ATAPI request sense key */
u_int8_t sense_cmd; /* ATAPI saved command */
u_int8_t ccb[16]; /* ATAPI command block */
struct atapi_sense sense_data; /* ATAPI request sense data */
u_int8_t sense_key; /* ATAPI request sense key */
u_int8_t sense_cmd; /* ATAPI saved command */
} atapi;
} u;
u_int32_t bytecount; /* bytes to transfer */
u_int32_t transfersize; /* bytes pr transfer */
caddr_t data; /* pointer to data buf */
int flags;
#define ATA_R_CONTROL 0x00000001
#define ATA_R_READ 0x00000002
#define ATA_R_WRITE 0x00000004
#define ATA_R_DMA 0x00000008
u_int8_t status; /* ATA status */
u_int8_t error; /* ATA error */
u_int8_t dmastat; /* DMA status */
#define ATA_R_ATAPI 0x00000010
#define ATA_R_QUIET 0x00000020
#define ATA_R_INTR_SEEN 0x00000040
#define ATA_R_TIMEOUT 0x00000080
u_int32_t bytecount; /* bytes to transfer */
u_int32_t transfersize; /* bytes pr transfer */
u_int32_t donecount; /* bytes transferred */
caddr_t data; /* pointer to data buf */
int flags;
#define ATA_R_CONTROL 0x0001
#define ATA_R_READ 0x0002
#define ATA_R_WRITE 0x0004
#define ATA_R_DMA 0x0008
#define ATA_R_ORDERED 0x00000100
#define ATA_R_AT_HEAD 0x00000200
#define ATA_R_REQUEUE 0x00000400
#define ATA_R_THREAD 0x00000800
#define ATA_R_DIRECT 0x00001000
#define ATA_R_ATAPI 0x0010
#define ATA_R_QUIET 0x0020
#define ATA_R_INTR_SEEN 0x0040
#define ATA_R_TIMEOUT 0x0080
#define ATA_R_DEBUG 0x10000000
#define ATA_R_ORDERED 0x0100
#define ATA_R_IMMEDIATE 0x0200
#define ATA_R_REQUEUE 0x0400
#define ATA_R_DEBUG 0x1000
void (*callback)(struct ata_request *request);
struct sema done; /* request done sema */
int retries; /* retry count */
int timeout; /* timeout for this cmd */
struct callout callout; /* callout management */
int result; /* result error code */
struct task task; /* task management */
struct bio *bio; /* bio for this request */
TAILQ_ENTRY(ata_request) sequence; /* sequence management */
TAILQ_ENTRY(ata_request) chain; /* list management */
u_int8_t status; /* ATA status */
u_int8_t error; /* ATA error */
u_int8_t dmastat; /* DMA status */
u_int32_t donecount; /* bytes transferred */
int result; /* result error code */
void (*callback)(struct ata_request *request);
struct sema done; /* request done sema */
int retries; /* retry count */
int timeout; /* timeout for this cmd */
struct callout callout; /* callout management */
struct task task; /* task management */
struct bio *bio; /* bio for this request */
int this; /* this request ID */
struct ata_composite *composite; /* for composite atomic ops */
void *driver; /* driver specific */
TAILQ_ENTRY(ata_request) chain; /* list management */
};
/* define this for debugging request processing */
#if 0
#if 1
#define ATA_DEBUG_RQ(request, string) \
{ \
if (request->flags & ATA_R_DEBUG) \
ata_prtdev(request->device, "req=%p %s " string "\n", \
request, ata_cmd2str(request)); \
device_printf(request->dev, "req=%p %s " string "\n", \
request, ata_cmd2str(request)); \
}
#else
#define ATA_DEBUG_RQ(request, string)
@ -251,27 +266,19 @@ struct ata_request {
/* structure describing an ATA/ATAPI device */
struct ata_device {
struct ata_channel *channel;
int unit; /* unit number */
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x10
device_t dev; /* device handle */
int unit; /* physical unit */
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x10
char *name; /* device name */
struct ata_params *param; /* ata param structure */
void *softc; /* ptr to softc for device */
void (*attach)(struct ata_device *atadev);
void (*detach)(struct ata_device *atadev);
void (*config)(struct ata_device *atadev);
void (*start)(struct ata_device *atadev);
int flags;
#define ATA_D_USE_CHS 0x0001
#define ATA_D_DETACHING 0x0002
#define ATA_D_MEDIA_CHANGED 0x0004
#define ATA_D_ENC_PRESENT 0x0008
int cmd; /* last cmd executed */
int mode; /* transfermode */
void (*setmode)(struct ata_device *atadev, int mode);
struct ata_params param; /* ata param structure */
int mode; /* current transfermode */
u_int32_t max_iosize; /* max IO size */
int cmd; /* last cmd executed */
int flags;
#define ATA_D_USE_CHS 0x0001
#define ATA_D_MEDIA_CHANGED 0x0002
#define ATA_D_ENC_PRESENT 0x0004
};
/* structure for holding DMA Physical Region Descriptors (PRD) entries */
@ -286,28 +293,29 @@ struct ata_dmasetprd_args {
int error;
};
struct ata_channel {};
/* structure holding DMA related information */
struct ata_dma {
bus_dma_tag_t dmatag; /* parent DMA tag */
bus_dma_tag_t cdmatag; /* control DMA tag */
bus_dmamap_t cdmamap; /* control DMA map */
bus_dma_tag_t ddmatag; /* data DMA tag */
bus_dmamap_t ddmamap; /* data DMA map */
void *dmatab; /* DMA transfer table */
bus_addr_t mdmatab; /* bus address of dmatab */
bus_dma_tag_t wdmatag; /* workspace DMA tag */
bus_dmamap_t wdmamap; /* workspace DMA map */
u_int8_t *workspace; /* workspace */
bus_addr_t wdmatab; /* bus address of dmatab */
bus_dma_tag_t dmatag; /* parent DMA tag */
bus_dma_tag_t sg_tag; /* SG list DMA tag */
bus_dmamap_t sg_map; /* SG list DMA map */
void *sg; /* DMA transfer table */
bus_addr_t sg_bus; /* bus address of dmatab */
bus_dma_tag_t data_tag; /* data DMA tag */
bus_dmamap_t data_map; /* data DMA map */
bus_dma_tag_t work_tag; /* workspace DMA tag */
bus_dmamap_t work_map; /* workspace DMA map */
u_int8_t *work; /* workspace */
bus_addr_t work_bus; /* bus address of dmatab */
u_int32_t alignment; /* DMA engine alignment */
u_int32_t boundary; /* DMA engine boundary */
u_int32_t max_iosize; /* DMA engine max IO size */
u_int32_t cur_iosize; /* DMA engine current IO size */
int flags;
#define ATA_DMA_READ 0x01 /* transaction is a read */
#define ATA_DMA_LOADED 0x02 /* DMA tables etc loaded */
#define ATA_DMA_ACTIVE 0x04 /* DMA transfer in progress */
u_int32_t alignment; /* DMA engine alignment */
u_int32_t boundary; /* DMA engine boundary */
u_int32_t max_iosize; /* DMA engine max IO size */
u_int32_t cur_iosize; /* DMA engine current IO size */
int flags;
#define ATA_DMA_READ 0x01 /* transaction is a read */
#define ATA_DMA_LOADED 0x02 /* DMA tables etc loaded */
#define ATA_DMA_ACTIVE 0x04 /* DMA transfer in progress */
void (*alloc)(struct ata_channel *ch);
void (*free)(struct ata_channel *ch);
@ -322,70 +330,59 @@ struct ata_dma {
struct ata_lowlevel {
int (*begin_transaction)(struct ata_request *request);
int (*end_transaction)(struct ata_request *request);
void (*interrupt)(void *channel);
void (*reset)(struct ata_channel *ch);
int (*command)(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature);
};
/* structure holding resources for an ATA channel */
struct ata_resource {
struct resource *res;
int offset;
struct resource *res;
int offset;
};
/* structure describing an ATA channel */
struct ata_channel {
struct device *dev; /* device handle */
int unit; /* channel number */
struct ata_resource r_io[ATA_MAX_RES];/* I/O resources */
struct resource *r_irq; /* interrupt of this channel */
void *ih; /* interrupt handle */
struct ata_lowlevel hw; /* lowlevel HW functions */
struct ata_dma *dma; /* DMA data / functions */
int flags; /* channel flags */
#define ATA_NO_SLAVE 0x01
#define ATA_USE_16BIT 0x02
#define ATA_ATAPI_DMA_RO 0x04
#define ATA_48BIT_ACTIVE 0x10
#define ATA_IMMEDIATE_MODE 0x20
#define ATA_HWGONE 0x40
device_t dev; /* device handle */
int unit; /* physical channel */
struct ata_resource r_io[ATA_MAX_RES];/* I/O resources */
struct resource *r_irq; /* interrupt of this channel */
void *ih; /* interrupt handle */
struct ata_lowlevel hw; /* lowlevel HW functions */
struct ata_dma *dma; /* DMA data / functions */
int flags; /* channel flags */
#define ATA_NO_SLAVE 0x01
#define ATA_USE_16BIT 0x02
#define ATA_ATAPI_DMA_RO 0x04
#define ATA_48BIT_ACTIVE 0x08
struct ata_device device[2]; /* devices on this channel */
#define MASTER 0x00
#define SLAVE 0x01
int devices; /* what is present */
#define ATA_ATA_MASTER 0x01
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
int devices; /* what is present */
#define ATA_ATA_MASTER 0x01
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
struct mtx state_mtx; /* state lock */
int state; /* ATA channel state */
#define ATA_IDLE 0x0000
#define ATA_ACTIVE 0x0001
#define ATA_STALL_QUEUE 0x0002
#define ATA_TIMEOUT 0x0004
struct mtx state_mtx; /* state lock */
int state; /* ATA channel state */
#define ATA_IDLE 0x0000
#define ATA_ACTIVE 0x0001
#define ATA_INTERRUPT 0x0002
#define ATA_TIMEOUT 0x0004
void (*reset)(struct ata_channel *);
int (*locking)(struct ata_channel *, int);
#define ATA_LF_LOCK 0x0001
#define ATA_LF_UNLOCK 0x0002
#define ATA_LF_WHICH 0x0004
struct mtx queue_mtx; /* queue lock */
TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */
struct ata_request *running; /* currently running request */
struct mtx queue_mtx; /* queue lock */
TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */
struct ata_request *freezepoint; /* composite freezepoint */
struct ata_request *running; /* currently running request */
};
/* disk bay/enclosure related */
#define ATA_LED_OFF 0x00
#define ATA_LED_RED 0x01
#define ATA_LED_GREEN 0x02
#define ATA_LED_ORANGE 0x03
#define ATA_LED_MASK 0x03
#define ATA_LED_OFF 0x00
#define ATA_LED_RED 0x01
#define ATA_LED_GREEN 0x02
#define ATA_LED_ORANGE 0x03
#define ATA_LED_MASK 0x03
/* externs */
extern int (*ata_ioctl_func)(struct ata_cmd *iocmd);
extern devclass_t ata_devclass;
extern int ata_wc;
@ -394,16 +391,11 @@ extern int ata_wc;
int ata_probe(device_t dev);
int ata_attach(device_t dev);
int ata_detach(device_t dev);
int ata_reinit(device_t dev);
int ata_suspend(device_t dev);
int ata_resume(device_t dev);
void ata_identify(driver_t *driver, device_t parent, int type, const char *name);
void ata_udelay(int interval);
int ata_printf(struct ata_channel *ch, int device, const char *fmt, ...) __printflike(3, 4);
int ata_prtdev(struct ata_device *atadev, const char *fmt, ...) __printflike(2, 3);
void ata_set_name(struct ata_device *atadev, char *name, int lun);
void ata_free_name(struct ata_device *atadev);
int ata_get_lun(u_int32_t *map);
int ata_test_lun(u_int32_t *map, int lun);
void ata_free_lun(u_int32_t *map, int lun);
char *ata_mode2str(int mode);
int ata_pmode(struct ata_params *ap);
int ata_wmode(struct ata_params *ap);
@ -411,33 +403,28 @@ int ata_umode(struct ata_params *ap);
int ata_limit_mode(struct ata_device *atadev, int mode, int maxmode);
/* ata-queue.c: */
int ata_reinit(struct ata_channel *ch);
void ata_start(struct ata_channel *ch);
int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count);
int ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout);
void ata_queue_request(struct ata_request *request);
void ata_start(device_t dev);
void ata_finish(struct ata_request *request);
void ata_catch_inflight(struct ata_channel *ch);
void ata_fail_requests(struct ata_channel *ch, struct ata_device *device);
void ata_fail_requests(struct ata_channel *ch, device_t dev);
char *ata_cmd2str(struct ata_request *request);
/* ata-lowlevel.c: */
void ata_generic_hw(struct ata_channel *ch);
int ata_generic_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature);
/* subdrivers */
void ad_attach(struct ata_device *atadev);
void acd_attach(struct ata_device *atadev);
void afd_attach(struct ata_device *atadev);
void ast_attach(struct ata_device *atadev);
void atapi_cam_attach_bus(struct ata_channel *ch);
void atapi_cam_detach_bus(struct ata_channel *ch);
void atapi_cam_reinit_bus(struct ata_channel *ch);
int ata_getparam(device_t parent, struct ata_device *atadev, u_int8_t command);
/* macros for alloc/free of ata_requests */
extern uma_zone_t ata_zone;
#define ata_alloc_request() uma_zalloc(ata_zone, M_NOWAIT | M_ZERO)
#define ata_free_request(request) uma_zfree(ata_zone, request)
MALLOC_DECLARE(M_ATA);
/* misc newbus defines */
#define GRANDPARENT(dev) device_get_parent(device_get_parent(dev))
/* macros to hide busspace uglyness */
#define ATA_INB(res, offset) \

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 ren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 ren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -61,8 +61,6 @@ static const struct pccard_product ata_pccard_products[] = {
{NULL}
};
MALLOC_DECLARE(M_ATA);
static int
ata_pccard_match(device_t dev)
{
@ -88,18 +86,6 @@ ata_pccard_match(device_t dev)
return(ENXIO);
}
static int
ata_pccard_locknoop(struct ata_channel *ch, int type)
{
return ch->unit;
}
static void
ata_pccard_setmode(struct ata_device *atadev, int mode)
{
atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
}
static int
ata_pccard_probe(device_t dev)
{
@ -145,8 +131,6 @@ ata_pccard_probe(device_t dev)
/* initialize softc for this channel */
ch->unit = 0;
ch->flags |= (ATA_USE_16BIT | ATA_NO_SLAVE);
ch->locking = ata_pccard_locknoop;
ch->device[MASTER].setmode = ata_pccard_setmode;
ata_generic_hw(ch);
return ata_probe(dev);
}
@ -157,8 +141,6 @@ ata_pccard_detach(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
int i;
free(ch->device[MASTER].param, M_ATA);
ch->device[MASTER].param = NULL;
ata_detach(dev);
if (ch->r_io[ATA_ALTSTAT].res != ch->r_io[ATA_DATA].res)
bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
@ -172,14 +154,14 @@ ata_pccard_detach(device_t dev)
static device_method_t ata_pccard_methods[] = {
/* device interface */
DEVMETHOD(device_probe, pccard_compat_probe),
DEVMETHOD(device_attach, pccard_compat_attach),
DEVMETHOD(device_detach, ata_pccard_detach),
DEVMETHOD(device_probe, pccard_compat_probe),
DEVMETHOD(device_attach, pccard_compat_attach),
DEVMETHOD(device_detach, ata_pccard_detach),
/* Card interface */
DEVMETHOD(card_compat_match, ata_pccard_match),
DEVMETHOD(card_compat_probe, ata_pccard_probe),
DEVMETHOD(card_compat_attach, ata_attach),
/* card interface */
DEVMETHOD(card_compat_match, ata_pccard_match),
DEVMETHOD(card_compat_probe, ata_pccard_probe),
DEVMETHOD(card_compat_attach, ata_attach),
{ 0, 0 }
};
@ -190,3 +172,4 @@ static driver_t ata_pccard_driver = {
};
DRIVER_MODULE(ata, pccard, ata_pccard_driver, ata_devclass, 0, 0);
MODULE_DEPEND(ata, ata, 1, 1, 1);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2002 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 2002 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <isa/isavar.h>
#include <dev/ata/ata-all.h>
#include <ata_if.h>
/* local vars */
struct ata_cbus_controller {
@ -54,11 +55,10 @@ struct ata_cbus_controller {
struct resource *bankio;
struct resource *irq;
void *ih;
void (*setmode)(struct ata_device *, int);
int (*locking)(struct ata_channel *, int);
struct mtx bank_mtx;
int current_bank;
int locked_bank;
int restart_bank;
int hardware_bank;
struct {
void (*function)(void *);
void *argument;
@ -67,8 +67,7 @@ struct ata_cbus_controller {
/* local prototypes */
static void ata_cbus_intr(void *);
static int ata_cbus_banking(struct ata_channel *, int);
static void ata_cbus_setmode(struct ata_device *, int);
static int ata_cbus_banking(device_t parent, device_t dev, int flags);
static int
ata_cbus_probe(device_t dev)
@ -162,10 +161,9 @@ ata_cbus_attach(device_t dev)
}
mtx_init(&ctlr->bank_mtx, "ATA cbus bank lock", NULL, MTX_DEF);
ctlr->current_bank = -1;
ctlr->hardware_bank = -1;
ctlr->locked_bank = -1;
ctlr->restart_bank = -1;
ctlr->locking = ata_cbus_banking;
ctlr->setmode = ata_cbus_setmode;;
if (!device_add_child(dev, "ata", 0))
return ENOMEM;
@ -229,41 +227,44 @@ ata_cbus_intr(void *data)
int unit;
for (unit = 0; unit < 2; unit++) {
if (!(ch = ctlr->interrupt[unit].argument))
continue;
if (ch->locking(ch, ATA_LF_WHICH) == unit)
if (!(ch = ctlr->interrupt[unit].argument))
continue;
if (ata_cbus_banking(device_get_parent(ch->dev), ch->dev,
ATA_LF_WHICH) == unit)
ctlr->interrupt[unit].function(ch);
}
}
static int
ata_cbus_banking(struct ata_channel *ch, int flags)
ata_cbus_banking(device_t parent, device_t dev, int flags)
{
struct ata_cbus_controller *ctlr =
device_get_softc(device_get_parent(ch->dev));
struct ata_cbus_controller *ctlr = device_get_softc(parent);
struct ata_channel *ch = device_get_softc(dev);
int res;
mtx_lock(&ctlr->bank_mtx);
switch (flags) {
case ATA_LF_LOCK:
if (ctlr->current_bank == -1)
ctlr->current_bank = ch->unit;
if (ctlr->current_bank == ch->unit)
if (ctlr->locked_bank == -1)
ctlr->locked_bank = ch->unit;
if (ctlr->locked_bank == ch->unit) {
ctlr->hardware_bank = ch->unit;
ATA_OUTB(ctlr->bankio, 0, ch->unit);
}
else
ctlr->restart_bank = ch->unit;
break;
case ATA_LF_UNLOCK:
if (ctlr->current_bank == ch->unit) {
ctlr->current_bank = -1;
if (ctlr->locked_bank == ch->unit) {
ctlr->locked_bank = -1;
if (ctlr->restart_bank != -1) {
if (ctlr->interrupt[ctlr->restart_bank].argument) {
mtx_unlock(&ctlr->bank_mtx);
ata_start(ctlr->interrupt[ctlr->restart_bank].argument);
mtx_lock(&ctlr->bank_mtx);
if ((ch = ctlr->interrupt[ctlr->restart_bank].argument)) {
ctlr->restart_bank = -1;
mtx_unlock(&ctlr->bank_mtx);
ata_start(ch->dev);
return -1;
}
ctlr->restart_bank = -1;
}
}
break;
@ -271,26 +272,24 @@ ata_cbus_banking(struct ata_channel *ch, int flags)
case ATA_LF_WHICH:
break;
}
res = ctlr->current_bank;
res = ctlr->locked_bank;
mtx_unlock(&ctlr->bank_mtx);
return res;
}
static void
ata_cbus_setmode(struct ata_device *atadev, int mode)
{
atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
}
static device_method_t ata_cbus_methods[] = {
/* device_interface */
DEVMETHOD(device_probe, ata_cbus_probe),
DEVMETHOD(device_attach, ata_cbus_attach),
/* device interface */
DEVMETHOD(device_probe, ata_cbus_probe),
DEVMETHOD(device_attach, ata_cbus_attach),
// DEVMETHOD(device_detach, ata_cbus_detach),
/* bus methods */
DEVMETHOD(bus_alloc_resource, ata_cbus_alloc_resource),
DEVMETHOD(bus_setup_intr, ata_cbus_setup_intr),
DEVMETHOD(bus_print_child, ata_cbus_print_child),
DEVMETHOD(bus_alloc_resource, ata_cbus_alloc_resource),
DEVMETHOD(bus_setup_intr, ata_cbus_setup_intr),
DEVMETHOD(bus_print_child, ata_cbus_print_child),
/* ATA methods */
DEVMETHOD(ata_locking, ata_cbus_banking),
{ 0, 0 }
};
@ -330,19 +329,17 @@ ata_cbussub_probe(device_t dev)
/* initialize softc for this channel */
ch->flags |= ATA_USE_16BIT;
ch->locking = ctlr->locking;
ch->device[MASTER].setmode = ctlr->setmode;
ch->device[SLAVE].setmode = ctlr->setmode;
ata_generic_hw(ch);
return ata_probe(dev);
}
static device_method_t ata_cbussub_methods[] = {
/* device interface */
DEVMETHOD(device_probe, ata_cbussub_probe),
DEVMETHOD(device_attach, ata_attach),
DEVMETHOD(device_detach, ata_detach),
DEVMETHOD(device_resume, ata_resume),
DEVMETHOD(device_probe, ata_cbussub_probe),
DEVMETHOD(device_attach, ata_attach),
DEVMETHOD(device_detach, ata_detach),
DEVMETHOD(device_suspend, ata_suspend),
DEVMETHOD(device_resume, ata_resume),
{ 0, 0 }
};
@ -353,3 +350,4 @@ static driver_t ata_cbussub_driver = {
};
DRIVER_MODULE(ata, atacbus, ata_cbussub_driver, ata_devclass, 0, 0);
MODULE_DEPEND(ata, ata, 1, 1, 1);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,101 +29,102 @@
*/
/* ATA commands */
#define ATA_NOP 0x00 /* NOP command */
#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */
#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */
#define ATA_ATAPI_RESET 0x08 /* reset ATAPI device */
#define ATA_READ 0x20 /* read command */
#define ATA_READ48 0x24 /* read command */
#define ATA_READ_DMA48 0x25 /* read w/DMA command */
#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */
#define ATA_READ_MUL48 0x29 /* read multi command */
#define ATA_WRITE 0x30 /* write command */
#define ATA_WRITE48 0x34 /* write command */
#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */
#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */
#define ATA_WRITE_MUL48 0x39 /* write multi command */
#define ATA_READ_FPDMA_QUEUED 0x60 /* read w/DMA NCQ */
#define ATA_WRITE_FPDMA_QUEUED 0x61 /* write w/DMA NCQ */
#define ATA_PACKET_CMD 0xa0 /* packet command */
#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/
#define ATA_SERVICE 0xa2 /* service command */
#define ATA_READ_MUL 0xc4 /* read multi command */
#define ATA_WRITE_MUL 0xc5 /* write multi command */
#define ATA_SET_MULTI 0xc6 /* set multi size command */
#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */
#define ATA_READ_DMA 0xc8 /* read w/DMA command */
#define ATA_WRITE_DMA 0xca /* write w/DMA command */
#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */
#define ATA_SLEEP 0xe6 /* sleep command */
#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */
#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */
#define ATA_ATA_IDENTIFY 0xec /* get ATA params */
#define ATA_SETFEATURES 0xef /* features command */
#define ATA_SF_SETXFER 0x03 /* set transfer mode */
#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */
#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */
#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */
#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */
#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */
#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */
#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */
#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */
#define ATA_NOP 0x00 /* NOP command */
#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */
#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */
#define ATA_DEVICE_RESET 0x08 /* reset ATAPI device */
#define ATA_READ 0x20 /* read command */
#define ATA_READ48 0x24 /* read command */
#define ATA_READ_DMA48 0x25 /* read w/DMA command */
#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */
#define ATA_READ_MUL48 0x29 /* read multi command */
#define ATA_WRITE 0x30 /* write command */
#define ATA_WRITE48 0x34 /* write command */
#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */
#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */
#define ATA_WRITE_MUL48 0x39 /* write multi command */
#define ATA_READ_FPDMA_QUEUED 0x60 /* read w/DMA NCQ */
#define ATA_WRITE_FPDMA_QUEUED 0x61 /* write w/DMA NCQ */
#define ATA_SEEK 0x70 /* seek */
#define ATA_PACKET_CMD 0xa0 /* packet command */
#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/
#define ATA_SERVICE 0xa2 /* service command */
#define ATA_READ_MUL 0xc4 /* read multi command */
#define ATA_WRITE_MUL 0xc5 /* write multi command */
#define ATA_SET_MULTI 0xc6 /* set multi size command */
#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */
#define ATA_READ_DMA 0xc8 /* read w/DMA command */
#define ATA_WRITE_DMA 0xca /* write w/DMA command */
#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */
#define ATA_SLEEP 0xe6 /* sleep command */
#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */
#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */
#define ATA_ATA_IDENTIFY 0xec /* get ATA params */
#define ATA_SETFEATURES 0xef /* features command */
#define ATA_SF_SETXFER 0x03 /* set transfer mode */
#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */
#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */
#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */
#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */
#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */
#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */
#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */
#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */
/* ATAPI commands */
#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */
#define ATAPI_REZERO 0x01 /* rewind */
#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
#define ATAPI_FORMAT 0x04 /* format unit */
#define ATAPI_READ 0x08 /* read data */
#define ATAPI_WRITE 0x0a /* write data */
#define ATAPI_WEOF 0x10 /* write filemark */
#define ATAPI_WF_WRITE 0x01
#define ATAPI_SPACE 0x11 /* space command */
#define ATAPI_SP_FM 0x01
#define ATAPI_SP_EOD 0x03
#define ATAPI_MODE_SELECT 0x15 /* mode select */
#define ATAPI_ERASE 0x19 /* erase */
#define ATAPI_MODE_SENSE 0x1a /* mode sense */
#define ATAPI_START_STOP 0x1b /* start/stop unit */
#define ATAPI_SS_LOAD 0x01
#define ATAPI_SS_RETENSION 0x02
#define ATAPI_SS_EJECT 0x04
#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */
#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
#define ATAPI_READ_BIG 0x28 /* read data */
#define ATAPI_WRITE_BIG 0x2a /* write data */
#define ATAPI_LOCATE 0x2b /* locate to position */
#define ATAPI_READ_POSITION 0x34 /* read position */
#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */
#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */
#define ATAPI_READ_BUFFER 0x3c /* read device buffer */
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
#define ATAPI_READ_TOC 0x43 /* get table of contents */
#define ATAPI_PLAY_10 0x45 /* play by lba */
#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */
#define ATAPI_PLAY_TRACK 0x48 /* play by track number */
#define ATAPI_PAUSE 0x4b /* pause audio operation */
#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */
#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */
#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */
#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
#define ATAPI_REPAIR_TRACK 0x58 /* repair track */
#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */
#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */
#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */
#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */
#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */
#define ATAPI_BLANK 0xa1 /* blank the media */
#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */
#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */
#define ATAPI_PLAY_12 0xa5 /* play by lba */
#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */
#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */
#define ATAPI_PLAY_CD 0xb4 /* universal play command */
#define ATAPI_SET_SPEED 0xbb /* set drive speed */
#define ATAPI_MECH_STATUS 0xbd /* get changer status */
#define ATAPI_READ_CD 0xbe /* read data */
#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */
#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */
#define ATAPI_REZERO 0x01 /* rewind */
#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
#define ATAPI_FORMAT 0x04 /* format unit */
#define ATAPI_READ 0x08 /* read data */
#define ATAPI_WRITE 0x0a /* write data */
#define ATAPI_WEOF 0x10 /* write filemark */
#define ATAPI_WF_WRITE 0x01
#define ATAPI_SPACE 0x11 /* space command */
#define ATAPI_SP_FM 0x01
#define ATAPI_SP_EOD 0x03
#define ATAPI_MODE_SELECT 0x15 /* mode select */
#define ATAPI_ERASE 0x19 /* erase */
#define ATAPI_MODE_SENSE 0x1a /* mode sense */
#define ATAPI_START_STOP 0x1b /* start/stop unit */
#define ATAPI_SS_LOAD 0x01
#define ATAPI_SS_RETENSION 0x02
#define ATAPI_SS_EJECT 0x04
#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */
#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
#define ATAPI_READ_BIG 0x28 /* read data */
#define ATAPI_WRITE_BIG 0x2a /* write data */
#define ATAPI_LOCATE 0x2b /* locate to position */
#define ATAPI_READ_POSITION 0x34 /* read position */
#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */
#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */
#define ATAPI_READ_BUFFER 0x3c /* read device buffer */
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
#define ATAPI_READ_TOC 0x43 /* get table of contents */
#define ATAPI_PLAY_10 0x45 /* play by lba */
#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */
#define ATAPI_PLAY_TRACK 0x48 /* play by track number */
#define ATAPI_PAUSE 0x4b /* pause audio operation */
#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */
#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */
#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */
#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
#define ATAPI_REPAIR_TRACK 0x58 /* repair track */
#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */
#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */
#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */
#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */
#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */
#define ATAPI_BLANK 0xa1 /* blank the media */
#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */
#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */
#define ATAPI_PLAY_12 0xa5 /* play by lba */
#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */
#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */
#define ATAPI_PLAY_CD 0xb4 /* universal play command */
#define ATAPI_SET_SPEED 0xbb /* set drive speed */
#define ATAPI_MECH_STATUS 0xbd /* get changer status */
#define ATAPI_READ_CD 0xbe /* read data */
#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/ata.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/bio.h>
#include <sys/bus.h>
@ -52,287 +53,225 @@ __FBSDID("$FreeBSD$");
#include <dev/ata/ata-pci.h>
#include <dev/ata/ata-disk.h>
#include <dev/ata/ata-raid.h>
#include <ata_if.h>
/* prototypes */
static void ad_detach(struct ata_device *);
static void ad_config(struct ata_device *);
static void ad_start(struct ata_device *);
static void ad_init(device_t);
static void ad_done(struct ata_request *);
static disk_open_t adopen;
static disk_strategy_t adstrategy;
static dumper_t addump;
void ad_print(struct ad_softc *);
static void ad_describe(device_t dev);
static int ad_version(u_int16_t);
static disk_strategy_t ad_strategy;
static dumper_t ad_dump;
/* internal vars */
/* local vars */
static MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver");
static u_int32_t adp_lun_map = 0;
void
ad_attach(struct ata_device *atadev)
static void
ad_identify(driver_t *driver, device_t parent)
{
ata_identify(driver, parent, -1, "ad");
}
static int
ad_probe(device_t dev)
{
return 0;
}
static int
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))
return EEXIST;
if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) {
ata_prtdev(atadev, "FAILURE - could not allocate driver storage\n");
atadev->attach = NULL;
return;
device_printf(dev, "out of memory\n");
device_set_softc(dev, NULL);
free(atadev, M_ATA);
return ENOMEM;
}
atadev->softc = adp;
adp->device = atadev;
device_set_ivars(dev, adp);
#ifdef ATA_STATIC_ID
adp->lun = (device_get_unit(atadev->channel->dev)<<1)+ATA_DEV(atadev->unit);
#else
adp->lun = ata_get_lun(&adp_lun_map);
#endif
ata_set_name(atadev, "ad", adp->lun);
adp->heads = atadev->param->heads;
adp->sectors = atadev->param->sectors;
adp->total_secs = atadev->param->cylinders * adp->heads * adp->sectors;
#ifdef PC98
/*
* During the BOOT process, the PC-98 BIOS sets fake geometry of
* xxxx/8/17 of the disk using 'INITIALIZE DEVICE PARAMETER (91h)'
* command. After this command, all access to the drive must be done
* via the new, fake geometry, rather than the old, native format.
* With ATA/ATAPI-6 or later, these parameters are obsolete, but
* PC-98s are still using them.
*
* This only really matters when we're talking to disks using CHS
* mode, not LBA mode. The CHS mode disks are still relatively
* common in these machines, so that case must be addressed.
*
* (ITF sets new CHS geometry to initialized disks.)
*
* obsolete54[0]: current cylinder
* obsolete54[1]: current heads
* obsolete54[2]: current sectors
* obsolete54[3-4]: current capacities(multiplied above 3 values)
*/
/* Get CHS geometry from set by Initialize Device Parameters command. */
if ((atadev->param->atavalid & ATA_FLAG_54_58) ||
(atadev->param->obsolete54[0] != 0 &&
atadev->param->obsolete54[1] != 0 &&
atadev->param->obsolete54[2] != 0)) {
adp->heads = atadev->param->obsolete54[1];
adp->sectors = atadev->param->obsolete54[2];
adp->total_secs = *(u_int32_t*)&(atadev->param->obsolete54[3]);
if (atadev->param.atavalid & ATA_FLAG_54_58) {
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);
}
#endif
mtx_init(&adp->queue_mtx, "ATA disk bioqueue lock", NULL, MTX_DEF);
bioq_init(&adp->queue);
lbasize = (u_int32_t)atadev->param->lba_size_1 |
((u_int32_t)atadev->param->lba_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)
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)
if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize)
adp->total_secs = lbasize;
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);
/* use the 48bit LBA size if valid */
if ((atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) &&
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;
/* setup the function ptrs */
atadev->detach = ad_detach;
atadev->config = ad_config;
atadev->start = ad_start;
/* init device parameters */
ad_init(dev);
/* config device features */
ad_config(atadev);
/* announce we are here */
ad_describe(dev);
/* lets create the disk device */
/* create the disk device */
adp->disk = disk_alloc();
adp->disk->d_open = adopen;
adp->disk->d_strategy = adstrategy;
adp->disk->d_dump = addump;
adp->disk->d_strategy = ad_strategy;
adp->disk->d_dump = ad_dump;
adp->disk->d_name = "ad";
adp->disk->d_drv1 = adp;
if (atadev->channel->dma)
adp->disk->d_maxsize = atadev->channel->dma->max_iosize;
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_sectorsize = DEV_BSIZE;
adp->disk->d_mediasize = DEV_BSIZE * (off_t)adp->total_secs;
adp->disk->d_fwsectors = adp->sectors;
adp->disk->d_fwheads = adp->heads;
adp->disk->d_unit = adp->lun;
adp->disk->d_unit = device_get_unit(dev);
disk_create(adp->disk, DISK_VERSION);
/* announce we are here */
ad_print(adp);
#ifdef DEV_ATARAID
ata_raiddisk_attach(adp);
#endif
}
static void
ad_detach(struct ata_device *atadev)
{
struct ad_softc *adp = atadev->softc;
#ifdef DEV_ATARAID
if (adp->flags & AD_F_RAID_SUBDISK)
ata_raiddisk_detach(adp);
#endif
disk_destroy(adp->disk);
ata_prtdev(atadev, "WARNING - removed from configuration\n");
mtx_lock(&adp->queue_mtx);
bioq_flush(&adp->queue, NULL, ENXIO);
mtx_unlock(&adp->queue_mtx);
mtx_destroy(&adp->queue_mtx);
ata_free_name(atadev);
ata_free_lun(&adp_lun_map, adp->lun);
atadev->attach = NULL;
atadev->detach = NULL;
atadev->start = NULL;
atadev->softc = NULL;
atadev->flags = 0;
free(adp, M_AD);
}
static void
ad_config(struct ata_device *atadev)
{
struct ad_softc *adp = atadev->softc;
/* enable read caching */
ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0);
/* enable write caching if enabled */
if (ata_wc)
ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0);
else
ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0);
/* use multiple sectors/interrupt if device supports it */
adp->max_iosize = DEV_BSIZE;
if (ad_version(atadev->param->version_major)) {
int secsperint = max(1, min(atadev->param->sectors_intr, 16));
if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint))
adp->max_iosize = secsperint * DEV_BSIZE;
}
device_add_child(dev, "subdisk", device_get_unit(dev));
bus_generic_attach(dev);
return 0;
}
static int
adopen(struct disk *dp)
ad_detach(device_t dev)
{
struct ad_softc *adp = dp->d_drv1;
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
struct ad_softc *adp = device_get_ivars(dev);
device_t *children;
int nchildren, i;
if (adp == NULL || adp->device->flags & ATA_D_DETACHING)
/* check that we have a valid disk to detach */
if (!device_get_ivars(dev))
return ENXIO;
/* detach & delete all children */
if (!device_get_children(dev, &children, &nchildren)) {
for (i = 0; i < nchildren; i++)
if (children[i])
device_delete_child(dev, children[i]);
free(children, M_TEMP);
}
/* detroy disk from the system so we dont get any further requests */
disk_destroy(adp->disk);
/* fail requests on the queue and any thats "in flight" for this device */
ata_fail_requests(ch, dev);
/* dont leave anything behind */
device_set_ivars(dev, NULL);
free(adp, M_AD);
device_set_softc(dev, NULL);
free(atadev, M_ATA);
return 0;
}
static void
ad_shutdown(device_t dev)
{
struct ata_device *atadev = device_get_softc(dev);
if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
ata_controlcmd(atadev, ATA_FLUSHCACHE, 0, 0, 0);
}
static int
ad_reinit(device_t dev)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
/* if detach pending flag set, return error */
if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATA_MASTER)) ||
((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATA_SLAVE))) {
return 1;
}
ad_init(dev);
return 0;
}
static void
adstrategy(struct bio *bp)
ad_strategy(struct bio *bp)
{
struct ad_softc *adp = bp->bio_disk->d_drv1;
mtx_lock(&adp->queue_mtx);
bioq_disksort(&adp->queue, bp);
mtx_unlock(&adp->queue_mtx);
ata_start(adp->device->channel);
}
static void
ad_start(struct ata_device *atadev)
{
struct ad_softc *adp = atadev->softc;
struct bio *bp;
device_t dev = bp->bio_disk->d_drv1;
struct ata_device *atadev = device_get_softc(dev);
struct ata_request *request;
/* remove request from drive queue */
mtx_lock(&adp->queue_mtx);
bp = bioq_first(&adp->queue);
if (!bp) {
mtx_unlock(&adp->queue_mtx);
return;
}
bioq_remove(&adp->queue, bp);
mtx_unlock(&adp->queue_mtx);
if (adp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
return;
}
if (!(request = ata_alloc_request())) {
ata_prtdev(atadev, "FAILURE - out of memory in start\n");
device_printf(dev, "FAILURE - out of memory in start\n");
biofinish(bp, NULL, ENOMEM);
return;
}
/* setup request */
request->device = atadev;
request->dev = dev;
request->bio = bp;
request->callback = ad_done;
request->timeout = 5;
request->retries = 2;
request->data = bp->bio_data;
request->bytecount = bp->bio_bcount;
/* convert LBA contents if this is an old non-LBA device */
if (atadev->flags & ATA_D_USE_CHS) {
int sector = (bp->bio_pblkno % adp->sectors) + 1;
int cylinder = bp->bio_pblkno / (adp->sectors * adp->heads);
int head = (bp->bio_pblkno %
(adp->sectors * adp->heads)) / adp->sectors;
request->u.ata.lba =
(sector & 0xff) | (cylinder & 0xffff) << 8 | (head & 0xf) << 24;
}
else
request->u.ata.lba = bp->bio_pblkno;
request->u.ata.lba = bp->bio_pblkno;
request->u.ata.count = request->bytecount / DEV_BSIZE;
request->transfersize = min(bp->bio_bcount, adp->max_iosize);
request->transfersize = min(bp->bio_bcount, atadev->max_iosize);
switch (bp->bio_cmd) {
case BIO_READ:
request->flags |= ATA_R_READ;
request->flags = ATA_R_READ;
if (atadev->mode >= ATA_DMA) {
request->u.ata.command = ATA_READ_DMA;
request->flags |= ATA_R_DMA;
}
else if (adp->max_iosize > DEV_BSIZE)
else if (atadev->max_iosize > DEV_BSIZE)
request->u.ata.command = ATA_READ_MUL;
else
request->u.ata.command = ATA_READ;
break;
case BIO_WRITE:
request->flags |= ATA_R_WRITE;
request->flags = ATA_R_WRITE;
if (atadev->mode >= ATA_DMA) {
request->u.ata.command = ATA_WRITE_DMA;
request->flags |= ATA_R_DMA;
}
else if (adp->max_iosize > DEV_BSIZE)
else if (atadev->max_iosize > DEV_BSIZE)
request->u.ata.command = ATA_WRITE_MUL;
else
request->u.ata.command = ATA_WRITE;
break;
default:
ata_prtdev(atadev, "FAILURE - unknown BIO operation\n");
device_printf(dev, "FAILURE - unknown BIO operation\n");
ata_free_request(request);
biofinish(bp, NULL, EIO);
return;
}
request->flags |= ATA_R_ORDERED;
ata_queue_request(request);
}
@ -350,25 +289,28 @@ ad_done(struct ata_request *request)
}
static int
addump(void *arg, void *virtual, vm_offset_t physical,
ad_dump(void *arg, void *virtual, vm_offset_t physical,
off_t offset, size_t length)
{
struct ata_request request;
struct disk *dp = arg;
struct ad_softc *adp = dp->d_drv1;
device_t dev = dp->d_drv1;
struct ata_device *atadev = device_get_softc(dev);
struct ad_softc *adp = device_get_ivars(dev);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_request request;
if (!adp)
return ENXIO;
bzero(&request, sizeof(struct ata_request));
request.device = adp->device;
request.dev = dev;
if (length) {
request.data = virtual;
request.bytecount = length;
request.transfersize = min(length, adp->max_iosize);
request.transfersize = min(length, atadev->max_iosize);
request.flags = ATA_R_WRITE;
if (adp->max_iosize > DEV_BSIZE)
if (atadev->max_iosize > DEV_BSIZE)
request.u.ata.command = ATA_WRITE_MUL;
else
request.u.ata.command = ATA_WRITE;
@ -379,13 +321,10 @@ addump(void *arg, void *virtual, vm_offset_t physical,
request.u.ata.command = ATA_FLUSHCACHE;
request.flags = ATA_R_CONTROL;
}
if (request.device->channel->
hw.begin_transaction(&request) == ATA_OP_CONTINUES) {
if (ch->hw.begin_transaction(&request) == ATA_OP_CONTINUES) {
do {
DELAY(20);
} while (request.device->channel->
hw.end_transaction(&request) == ATA_OP_CONTINUES);
} while (ch->hw.end_transaction(&request) == ATA_OP_CONTINUES);
ata_finish(&request);
}
if (request.status & ATA_S_ERROR)
@ -393,43 +332,75 @@ addump(void *arg, void *virtual, vm_offset_t physical,
return 0;
}
void
ad_print(struct ad_softc *adp)
static void
ad_init(device_t dev)
{
if (bootverbose) {
ata_prtdev(adp->device, "<%.40s/%.8s> ATA-%d disk at ata%d-%s\n",
adp->device->param->model, adp->device->param->revision,
ad_version(adp->device->param->version_major),
device_get_unit(adp->device->channel->dev),
(adp->device->unit == ATA_MASTER) ? "master" : "slave");
struct ata_device *atadev = device_get_softc(dev);
ata_prtdev(adp->device,
"%lluMB (%llu sectors), %llu C, %u H, %u S, %u B\n",
(unsigned long long)(adp->total_secs /
((1024L*1024L)/DEV_BSIZE)),
(unsigned long long)adp->total_secs,
(unsigned long long)(adp->total_secs /
(adp->heads * adp->sectors)),
adp->heads, adp->sectors, DEV_BSIZE);
ATA_SETMODE(GRANDPARENT(dev), dev);
ata_prtdev(adp->device, "%d secs/int, %d depth queue, %s%s\n",
adp->max_iosize / DEV_BSIZE, adp->num_tags + 1,
(adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
ata_mode2str(adp->device->mode));
/* enable read caching */
ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0);
/* enable write caching if enabled */
if (ata_wc)
ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0);
else
ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0);
/* use multiple sectors/interrupt if device supports it */
if (ad_version(atadev->param.version_major)) {
int secsperint = max(1, min(atadev->param.sectors_intr, 16));
if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint))
atadev->max_iosize = secsperint * DEV_BSIZE;
}
else
atadev->max_iosize = DEV_BSIZE;
}
void
ad_describe(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 = device_get_ivars(dev);
u_int8_t *marker, vendor[64], product[64];
/* try to seperate the ATA model string into vendor and model parts */
if ((marker = index(atadev->param.model, ' ')) ||
(marker = index(atadev->param.model, '-'))) {
int len = (marker - atadev->param.model);
strncpy(vendor, atadev->param.model, len);
vendor[len++] = 0;
strcat(vendor, " ");
strncpy(product, atadev->param.model + len, 40 - len);
vendor[40 - len] = 0;
}
else {
ata_prtdev(adp->device,
"%lluMB <%.40s/%.8s> [%lld/%d/%d] at ata%d-%s %s%s\n",
(unsigned long long)(adp->total_secs /
((1024L * 1024L) / DEV_BSIZE)),
adp->device->param->model, adp->device->param->revision,
(unsigned long long)(adp->total_secs /
(adp->heads * adp->sectors)),
adp->heads, adp->sectors,
device_get_unit(adp->device->channel->dev),
(adp->device->unit == ATA_MASTER) ? "master" : "slave",
(adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
ata_mode2str(adp->device->mode));
if (!strncmp(atadev->param.model, "ST", 2))
strcpy(vendor, "Seagate ");
else
strcpy(vendor, "");
strncpy(product, atadev->param.model, 40);
}
device_printf(dev, "%lluMB <%s%s %.8s> at ata%d-%s %s%s\n",
(unsigned long long)(adp->total_secs / (1048576 / DEV_BSIZE)),
vendor, product, atadev->param.revision,
device_get_unit(ch->dev),
(atadev->unit == ATA_MASTER) ? "master" : "slave",
(adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
ata_mode2str(atadev->mode));
if (bootverbose) {
device_printf(dev, "%llu sectors [%lldC/%dH/%dS] "
"%d sectors/interrupt %d depth queue\n",
(unsigned long long)adp->total_secs,
(unsigned long long)(adp->total_secs /
(adp->heads * adp->sectors)),
adp->heads, adp->sectors, atadev->max_iosize / DEV_BSIZE,
adp->num_tags + 1);
}
}
@ -445,3 +416,45 @@ ad_version(u_int16_t version)
return bit;
return 0;
}
static device_method_t ad_methods[] = {
/* device interface */
DEVMETHOD(device_identify, ad_identify),
DEVMETHOD(device_probe, ad_probe),
DEVMETHOD(device_attach, ad_attach),
DEVMETHOD(device_detach, ad_detach),
DEVMETHOD(device_shutdown, ad_shutdown),
/* ATA methods */
DEVMETHOD(ata_reinit, ad_reinit),
{ 0, 0 }
};
static driver_t ad_driver = {
"ad",
ad_methods,
sizeof(struct ad_softc)
};
devclass_t ad_devclass;
static int
ad_modevent(module_t mod, int what, void *arg)
{
device_t *devs;
int ndevs, i;
if (what == MOD_UNLOAD) {
if (!devclass_get_devices(ad_devclass, &devs, &ndevs) && devs) {
for (i = 0; i < ndevs; i++)
device_delete_child(device_get_parent(devs[i]), devs[i]);
free(devs, M_TEMP);
}
}
return 0;
}
DRIVER_MODULE(ad, ata, ad_driver, ad_devclass, ad_modevent, NULL);
MODULE_VERSION(ad, 1);
MODULE_DEPEND(ad, ata, 1, 1, 1);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,22 +30,20 @@
/* structure describing an ATA disk */
struct ad_softc {
struct ata_device *device; /* ptr to device softc */
int lun; /* logical unit number */
u_int64_t total_secs; /* total # of sectors (LBA) */
u_int8_t heads;
u_int8_t sectors;
u_int32_t transfersize; /* size of each transfer */
int num_tags; /* number of tags supported */
int max_iosize; /* max transfer HW supports */
int flags; /* drive flags */
#define AD_F_LABELLING 0x0001
#define AD_F_CHS_USED 0x0002
#define AD_F_32B_ENABLED 0x0004
#define AD_F_TAG_ENABLED 0x0008
#define AD_F_RAID_SUBDISK 0x0010
u_int64_t total_secs; /* total # of sectors (LBA) */
u_int8_t heads;
u_int8_t sectors;
u_int32_t transfersize; /* size of each transfer */
int num_tags; /* number of tags supported */
int flags; /* drive flags */
#define AD_F_LABELLING 0x0001
#define AD_F_CHS_USED 0x0002
#define AD_F_32B_ENABLED 0x0004
#define AD_F_TAG_ENABLED 0x0008
#define AD_F_RAID_SUBDISK 0x0010
struct mtx queue_mtx; /* bio queue lock */
struct bio_queue_head queue; /* head of request queue */
struct disk *disk; /* disklabel/slice stuff */
struct disk *disk; /* disklabel/slice stuff */
};
extern devclass_t ad_devclass;

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -57,8 +57,8 @@ static int ata_dmaunload(struct ata_channel *);
static MALLOC_DEFINE(M_ATADMA, "ATA DMA", "ATA driver DMA");
/* misc defines */
#define MAXTABSZ PAGE_SIZE
#define MAXWSPCSZ PAGE_SIZE
#define MAXTABSZ PAGE_SIZE
#define MAXWSPCSZ PAGE_SIZE
struct ata_dc_cb_args {
bus_addr_t maddr;
@ -104,51 +104,51 @@ ata_dmaalloc(struct ata_channel *ch)
if (bus_dma_tag_create(ch->dma->dmatag, PAGE_SIZE, PAGE_SIZE,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
NULL, NULL, MAXTABSZ, 1, MAXTABSZ,
0, NULL, NULL, &ch->dma->cdmatag))
0, NULL, NULL, &ch->dma->sg_tag))
goto error;
if (bus_dma_tag_create(ch->dma->dmatag,ch->dma->alignment,ch->dma->boundary,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
NULL, NULL, 256 * DEV_BSIZE,
ATA_DMA_ENTRIES, ch->dma->max_iosize,
BUS_DMA_ALLOCNOW, NULL, NULL, &ch->dma->ddmatag))
BUS_DMA_ALLOCNOW, NULL, NULL, &ch->dma->data_tag))
goto error;
if (bus_dmamem_alloc(ch->dma->cdmatag, (void **)&ch->dma->dmatab, 0,
&ch->dma->cdmamap))
if (bus_dmamem_alloc(ch->dma->sg_tag, (void **)&ch->dma->sg, 0,
&ch->dma->sg_map))
goto error;
if (bus_dmamap_load(ch->dma->cdmatag, ch->dma->cdmamap, ch->dma->dmatab,
if (bus_dmamap_load(ch->dma->sg_tag, ch->dma->sg_map, ch->dma->sg,
MAXTABSZ, ata_dmasetupc_cb, &ccba, 0) || ccba.error) {
bus_dmamem_free(ch->dma->cdmatag, ch->dma->dmatab, ch->dma->cdmamap);
bus_dmamem_free(ch->dma->sg_tag, ch->dma->sg, ch->dma->sg_map);
goto error;
}
ch->dma->mdmatab = ccba.maddr;
ch->dma->sg_bus = ccba.maddr;
if (bus_dmamap_create(ch->dma->ddmatag, 0, &ch->dma->ddmamap))
if (bus_dmamap_create(ch->dma->data_tag, 0, &ch->dma->data_map))
goto error;
if (bus_dma_tag_create(ch->dma->dmatag, PAGE_SIZE, PAGE_SIZE,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
NULL, NULL, MAXWSPCSZ, 1, MAXWSPCSZ,
0, NULL, NULL, &ch->dma->wdmatag))
0, NULL, NULL, &ch->dma->work_tag))
goto error;
if (bus_dmamem_alloc(ch->dma->wdmatag, (void **)&ch->dma->workspace, 0,
&ch->dma->wdmamap))
if (bus_dmamem_alloc(ch->dma->work_tag, (void **)&ch->dma->work, 0,
&ch->dma->work_map))
goto error;
if (bus_dmamap_load(ch->dma->wdmatag, ch->dma->wdmamap, ch->dma->workspace,
if (bus_dmamap_load(ch->dma->work_tag, ch->dma->work_map,ch->dma->work,
MAXWSPCSZ, ata_dmasetupc_cb, &ccba, 0) || ccba.error) {
bus_dmamem_free(ch->dma->wdmatag, ch->dma->workspace, ch->dma->wdmamap);
bus_dmamem_free(ch->dma->work_tag,ch->dma->work, ch->dma->work_map);
goto error;
}
ch->dma->wdmatab = ccba.maddr;
ch->dma->work_bus = ccba.maddr;
return;
error:
ata_printf(ch, -1, "WARNING - DMA allocation failed, disabling DMA\n");
device_printf(ch->dev, "WARNING - DMA allocation failed, disabling DMA\n");
ata_dmafree(ch);
free(ch->dma, M_ATADMA);
ch->dma = NULL;
@ -157,35 +157,35 @@ ata_dmaalloc(struct ata_channel *ch)
static void
ata_dmafree(struct ata_channel *ch)
{
if (ch->dma->wdmatab) {
bus_dmamap_unload(ch->dma->wdmatag, ch->dma->wdmamap);
bus_dmamem_free(ch->dma->wdmatag, ch->dma->workspace, ch->dma->wdmamap);
ch->dma->wdmatab = 0;
ch->dma->wdmamap = NULL;
ch->dma->workspace = NULL;
if (ch->dma->work_bus) {
bus_dmamap_unload(ch->dma->work_tag, ch->dma->work_map);
bus_dmamem_free(ch->dma->work_tag, ch->dma->work, ch->dma->work_map);
ch->dma->work_bus = 0;
ch->dma->work_map = NULL;
ch->dma->work = NULL;
}
if (ch->dma->wdmatag) {
bus_dma_tag_destroy(ch->dma->wdmatag);
ch->dma->wdmatag = NULL;
if (ch->dma->work_tag) {
bus_dma_tag_destroy(ch->dma->work_tag);
ch->dma->work_tag = NULL;
}
if (ch->dma->mdmatab) {
bus_dmamap_unload(ch->dma->cdmatag, ch->dma->cdmamap);
bus_dmamem_free(ch->dma->cdmatag, ch->dma->dmatab, ch->dma->cdmamap);
ch->dma->mdmatab = 0;
ch->dma->cdmamap = NULL;
ch->dma->dmatab = NULL;
if (ch->dma->sg_bus) {
bus_dmamap_unload(ch->dma->sg_tag, ch->dma->sg_map);
bus_dmamem_free(ch->dma->sg_tag, ch->dma->sg, ch->dma->sg_map);
ch->dma->sg_bus = 0;
ch->dma->sg_map = NULL;
ch->dma->sg = NULL;
}
if (ch->dma->ddmamap) {
bus_dmamap_destroy(ch->dma->ddmatag, ch->dma->ddmamap);
ch->dma->ddmamap = NULL;
if (ch->dma->data_map) {
bus_dmamap_destroy(ch->dma->data_tag, ch->dma->data_map);
ch->dma->data_map = NULL;
}
if (ch->dma->cdmatag) {
bus_dma_tag_destroy(ch->dma->cdmatag);
ch->dma->cdmatag = NULL;
if (ch->dma->sg_tag) {
bus_dma_tag_destroy(ch->dma->sg_tag);
ch->dma->sg_tag = NULL;
}
if (ch->dma->ddmatag) {
bus_dma_tag_destroy(ch->dma->ddmatag);
ch->dma->ddmatag = NULL;
if (ch->dma->data_tag) {
bus_dma_tag_destroy(ch->dma->data_tag);
ch->dma->data_tag = NULL;
}
if (ch->dma->dmatag) {
bus_dma_tag_destroy(ch->dma->dmatag);
@ -213,38 +213,41 @@ ata_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
static int
ata_dmaload(struct ata_device *atadev, caddr_t data, int32_t count, int dir)
{
struct ata_channel *ch = atadev->channel;
struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev));
struct ata_dmasetprd_args cba;
if (ch->dma->flags & ATA_DMA_LOADED) {
ata_prtdev(atadev, "FAILURE - already active DMA on this device\n");
device_printf(atadev->dev,
"FAILURE - already active DMA on this device\n");
return -1;
}
if (!count) {
ata_prtdev(atadev, "FAILURE - zero length DMA transfer attempted\n");
device_printf(atadev->dev,
"FAILURE - zero length DMA transfer attempted\n");
return -1;
}
if (((uintptr_t)data & (ch->dma->alignment - 1)) ||
(count & (ch->dma->alignment - 1))) {
ata_prtdev(atadev, "FAILURE - non aligned DMA transfer attempted\n");
device_printf(atadev->dev,
"FAILURE - non aligned DMA transfer attempted\n");
return -1;
}
if (count > ch->dma->max_iosize) {
ata_prtdev(atadev,
"FAILURE - oversized DMA transfer attempted %d > %d\n",
count, ch->dma->max_iosize);
device_printf(atadev->dev,
"FAILURE - oversized DMA transfer attempted %d > %d\n",
count, ch->dma->max_iosize);
return -1;
}
cba.dmatab = ch->dma->dmatab;
cba.dmatab = ch->dma->sg;
bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_PREWRITE);
bus_dmamap_sync(ch->dma->sg_tag, ch->dma->sg_map, BUS_DMASYNC_PREWRITE);
if (bus_dmamap_load(ch->dma->ddmatag, ch->dma->ddmamap, data, count,
if (bus_dmamap_load(ch->dma->data_tag, ch->dma->data_map, data, count,
ch->dma->setprd, &cba, 0) || cba.error)
return -1;
bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap,
bus_dmamap_sync(ch->dma->data_tag, ch->dma->data_map,
dir ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
ch->dma->cur_iosize = count;
@ -255,12 +258,12 @@ ata_dmaload(struct ata_device *atadev, caddr_t data, int32_t count, int dir)
int
ata_dmaunload(struct ata_channel *ch)
{
bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_POSTWRITE);
bus_dmamap_sync(ch->dma->sg_tag, ch->dma->sg_map, BUS_DMASYNC_POSTWRITE);
bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap,
bus_dmamap_sync(ch->dma->data_tag, ch->dma->data_map,
(ch->dma->flags & ATA_DMA_READ) != 0 ?
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(ch->dma->ddmatag, ch->dma->ddmamap);
bus_dmamap_unload(ch->dma->data_tag, ch->dma->data_map);
ch->dma->cur_iosize = 0;
ch->dma->flags &= ~ATA_DMA_LOADED;

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -49,27 +49,15 @@ __FBSDID("$FreeBSD$");
/* local vars */
static struct isa_pnp_id ata_ids[] = {
{0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */
{0x0106d041, "Plus Hardcard II"}, /* PNP0601 */
{0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */
{0x0306d041, "Generic ATA"}, /* PNP0603 */
{0x0006d041, "Generic ESDI/IDE/ATA controller"}, /* PNP0600 */
{0x0106d041, "Plus Hardcard II"}, /* PNP0601 */
{0x0206d041, "Plus Hardcard IIXL/EZ"}, /* PNP0602 */
{0x0306d041, "Generic ATA"}, /* PNP0603 */
/* PNP0680 */
{0x8006d041, "Standard bus mastering IDE hard disk controller"},
{0x8006d041, "Standard bus mastering IDE hard disk controller"},
{0}
};
static int
ata_isa_locknoop(struct ata_channel *ch, int type)
{
return ch->unit;
}
static void
ata_isa_setmode(struct ata_device *atadev, int mode)
{
atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
}
static int
ata_isa_probe(device_t dev)
{
@ -115,18 +103,16 @@ ata_isa_probe(device_t dev)
/* initialize softc for this channel */
ch->unit = 0;
ch->flags |= ATA_USE_16BIT;
ch->locking = ata_isa_locknoop;
ch->device[MASTER].setmode = ata_isa_setmode;
ch->device[SLAVE].setmode = ata_isa_setmode;
ata_generic_hw(ch);
return ata_probe(dev);
}
static device_method_t ata_isa_methods[] = {
/* device interface */
DEVMETHOD(device_probe, ata_isa_probe),
DEVMETHOD(device_attach, ata_attach),
DEVMETHOD(device_resume, ata_resume),
DEVMETHOD(device_probe, ata_isa_probe),
DEVMETHOD(device_attach, ata_attach),
DEVMETHOD(device_suspend, ata_suspend),
DEVMETHOD(device_resume, ata_resume),
{ 0, 0 }
};
@ -137,3 +123,4 @@ static driver_t ata_isa_driver = {
};
DRIVER_MODULE(ata, isa, ata_isa_driver, ata_devclass, 0, 0);
MODULE_DEPEND(ata, ata, 1, 1, 1);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,9 +32,11 @@ __FBSDID("$FreeBSD$");
#include "opt_ata.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ata.h>
#include <sys/kernel.h>
#include <sys/endian.h>
#include <sys/ata.h>
#include <sys/conf.h>
#include <sys/ctype.h>
#include <sys/bus.h>
#include <sys/sema.h>
#include <sys/taskqueue.h>
@ -42,17 +44,108 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-commands.h>
#include <dev/ata/ata-pci.h>
#include <ata_if.h>
/* prototypes */
static int ata_begin_transaction(struct ata_request *);
static int ata_end_transaction(struct ata_request *);
static void ata_generic_reset(struct ata_channel *);
static int ata_wait(struct ata_device *, u_int8_t);
static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t);
static void ata_pio_read(struct ata_request *, int);
static void ata_pio_write(struct ata_request *, int);
static void bswap(int8_t *, int);
static void btrim(int8_t *, int);
static void bpack(int8_t *, int8_t *, int);
/* local vars */
static int atadebug = 0;
/* get device parameter page from device */
int
ata_getparam(device_t parent, struct ata_device *atadev, u_int8_t command)
{
struct ata_channel *ch = device_get_softc(parent);
int error = 0, retry = 0;
do {
if (retry++ > 4) {
if (bootverbose)
printf("ata%d-%s: %s-identify retries exceeded\n", ch->unit,
atadev->unit == ATA_MASTER ? "master" : "slave",
command == ATA_ATAPI_IDENTIFY ? "ATAPI" : "ATA");
error = ENXIO;
break;
}
/* select device */
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit);
/* disable interrupt */
ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT | ATA_A_IDS);
/* ready to issue command ? */
if ((error = ata_wait(ch, atadev, 0)) < 0) {
printf("ata%d-%s: timeout sending %s-identify error=%d\n",
device_get_unit(parent),
atadev->unit == ATA_MASTER ? "master" : "slave",
command == ATA_ATAPI_IDENTIFY ? "ATAPI" : "ATA", error);
error = ENXIO;
break;
}
/* select device */
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit);
/* issue command */
ATA_IDX_OUTB(ch, ATA_CMD, command);
} while (ata_wait(ch, atadev, ATA_S_DRQ));
if (!error) {
ATA_IDX_INSW_STRM(ch, ATA_DATA, (void *)&atadev->param,
sizeof(struct ata_params)/sizeof(int16_t));
ATA_IDX_INB(ch, ATA_STATUS);
}
if (!error && (isprint(atadev->param.model[0]) ||
isprint(atadev->param.model[1]))) {
struct ata_params *atacap = &atadev->param;
#if BYTE_ORDER == BIG_ENDIAN
int16_t *ptr;
for (ptr = (int16_t *)atacap;
ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) {
*ptr = bswap16(*ptr);
}
#endif
if (!(!strncmp(atacap->model, "FX", 2) ||
!strncmp(atacap->model, "NEC", 3) ||
!strncmp(atacap->model, "Pioneer", 7) ||
!strncmp(atacap->model, "SHARP", 5))) {
bswap(atacap->model, sizeof(atacap->model));
bswap(atacap->revision, sizeof(atacap->revision));
bswap(atacap->serial, sizeof(atacap->serial));
}
btrim(atacap->model, sizeof(atacap->model));
bpack(atacap->model, atacap->model, sizeof(atacap->model));
btrim(atacap->revision, sizeof(atacap->revision));
bpack(atacap->revision, atacap->revision, sizeof(atacap->revision));
btrim(atacap->serial, sizeof(atacap->serial));
bpack(atacap->serial, atacap->serial, sizeof(atacap->serial));
if (bootverbose)
printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n",
ch->unit, atadev->unit == ATA_MASTER ? "master":"slave",
ata_mode2str(ata_pmode(atacap)),
ata_mode2str(ata_wmode(atacap)),
ata_mode2str(ata_umode(atacap)),
(atacap->hwres & ATA_CABLE_ID) ? "80":"40");
}
else {
if (!error)
error = ENXIO;
}
return error;
}
/*
* low level ATA functions
@ -70,14 +163,8 @@ ata_generic_hw(struct ata_channel *ch)
static int
ata_begin_transaction(struct ata_request *request)
{
struct ata_channel *ch = request->device->channel;
/* safetybelt for HW that went away */
if (!request->device->param || request->device->channel->flags&ATA_HWGONE) {
request->retries = 0;
request->result = ENXIO;
return ATA_OP_FINISHED;
}
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
struct ata_device *atadev = device_get_softc(request->dev);
ATA_DEBUG_RQ(request, "begin transaction");
@ -96,17 +183,17 @@ ata_begin_transaction(struct ata_request *request)
int write = (request->flags & ATA_R_WRITE);
/* issue command */
if (ch->hw.command(request->device, request->u.ata.command,
if (ch->hw.command(atadev, request->u.ata.command,
request->u.ata.lba, request->u.ata.count,
request->u.ata.feature)) {
ata_prtdev(request->device, "error issueing %s command\n",
device_printf(request->dev, "error issueing %s command\n",
ata_cmd2str(request));
request->result = EIO;
break;
}
/* device reset doesn't interrupt */
if (request->u.ata.command == ATA_ATAPI_RESET) {
if (request->u.ata.command == ATA_DEVICE_RESET) {
int timeout = 1000000;
do {
DELAY(10);
@ -119,9 +206,9 @@ ata_begin_transaction(struct ata_request *request)
/* if write command output the data */
if (write) {
if (ata_wait(request->device,
if (ata_wait(ch, atadev,
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
ata_prtdev(request->device,"timeout waiting for write DRQ");
device_printf(request->dev,"timeout waiting for write DRQ");
request->result = EIO;
break;
}
@ -133,18 +220,18 @@ ata_begin_transaction(struct ata_request *request)
/* ATA DMA data transfer commands */
case ATA_R_DMA:
/* check sanity, setup SG list and DMA engine */
if (ch->dma->load(request->device, request->data, request->bytecount,
if (ch->dma->load(atadev, request->data, request->bytecount,
request->flags & ATA_R_READ)) {
ata_prtdev(request->device, "setting up DMA failed\n");
device_printf(request->dev, "setting up DMA failed\n");
request->result = EIO;
break;
}
/* issue command */
if (ch->hw.command(request->device, request->u.ata.command,
if (ch->hw.command(atadev, request->u.ata.command,
request->u.ata.lba, request->u.ata.count,
request->u.ata.feature)) {
ata_prtdev(request->device, "error issueing %s command\n",
device_printf(request->dev, "error issueing %s command\n",
ata_cmd2str(request));
request->result = EIO;
break;
@ -152,7 +239,7 @@ ata_begin_transaction(struct ata_request *request)
/* start DMA engine */
if (ch->dma->start(ch)) {
ata_prtdev(request->device, "error starting DMA\n");
device_printf(request->dev, "error starting DMA\n");
request->result = EIO;
break;
}
@ -162,8 +249,7 @@ ata_begin_transaction(struct ata_request *request)
case ATA_R_ATAPI:
/* is this just a POLL DSC command ? */
if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
ATA_IDX_OUTB(ch, ATA_DRIVE,
ATA_D_IBM | request->device->unit);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit);
DELAY(10);
if (!(ATA_IDX_INB(ch, ATA_ALTSTAT)&ATA_S_DSC))
request->result = EBUSY;
@ -171,15 +257,15 @@ ata_begin_transaction(struct ata_request *request)
}
/* start ATAPI operation */
if (ch->hw.command(request->device, ATA_PACKET_CMD,
if (ch->hw.command(atadev, ATA_PACKET_CMD,
request->transfersize << 8, 0, 0)) {
ata_prtdev(request->device, "error issuing ATA PACKET command\n");
device_printf(request->dev, "error issuing ATA PACKET command\n");
request->result = EIO;
break;
}
/* command interrupt device ? just return and wait for interrupt */
if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR)
if ((atadev->param.config & ATA_DRQ_MASK) == ATA_DRQ_INTR)
return ATA_OP_CONTINUES;
/* wait for ready to write ATAPI command block */
@ -195,8 +281,7 @@ ata_begin_transaction(struct ata_request *request)
DELAY(20);
}
if (timeout <= 0) {
ata_prtdev(request->device,
"timeout waiting for ATAPI ready\n");
device_printf(request->dev,"timeout waiting for ATAPI ready\n");
request->result = EIO;
break;
}
@ -208,15 +293,14 @@ ata_begin_transaction(struct ata_request *request)
/* output actual command block */
ATA_IDX_OUTSW_STRM(ch, ATA_DATA,
(int16_t *)request->u.atapi.ccb,
(request->device->param->config & ATA_PROTO_MASK) ==
(atadev->param.config & ATA_PROTO_MASK) ==
ATA_PROTO_ATAPI_12 ? 6 : 8);
return ATA_OP_CONTINUES;
case ATA_R_ATAPI|ATA_R_DMA:
/* is this just a POLL DSC command ? */
if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
ATA_IDX_OUTB(ch, ATA_DRIVE,
ATA_D_IBM | request->device->unit);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit);
DELAY(10);
if (!(ATA_IDX_INB(ch, ATA_ALTSTAT)&ATA_S_DSC))
request->result = EBUSY;
@ -224,18 +308,16 @@ ata_begin_transaction(struct ata_request *request)
}
/* check sanity, setup SG list and DMA engine */
if (ch->dma->load(request->device,
request->data,
request->bytecount,
request->flags & ATA_R_READ)) {
ata_prtdev(request->device, "setting up DMA failed\n");
if (ch->dma->load(atadev, request->data, request->bytecount,
request->flags & ATA_R_READ)) {
device_printf(request->dev, "setting up DMA failed\n");
request->result = EIO;
break;
}
/* start ATAPI operation */
if (ch->hw.command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) {
ata_prtdev(request->device, "error issuing ATAPI packet command\n");
if (ch->hw.command(atadev, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) {
device_printf(request->dev, "error issuing ATAPI packet command\n");
request->result = EIO;
break;
}
@ -253,7 +335,7 @@ ata_begin_transaction(struct ata_request *request)
DELAY(20);
}
if (timeout <= 0) {
ata_prtdev(request->device,"timeout waiting for ATAPI ready\n");
device_printf(request->dev,"timeout waiting for ATAPI ready\n");
request->result = EIO;
break;
}
@ -265,7 +347,7 @@ ata_begin_transaction(struct ata_request *request)
/* output actual command block */
ATA_IDX_OUTSW_STRM(ch, ATA_DATA,
(int16_t *)request->u.atapi.ccb,
(request->device->param->config & ATA_PROTO_MASK) ==
(atadev->param.config & ATA_PROTO_MASK) ==
ATA_PROTO_ATAPI_12 ? 6 : 8);
/* start DMA engine */
@ -285,7 +367,8 @@ ata_begin_transaction(struct ata_request *request)
static int
ata_end_transaction(struct ata_request *request)
{
struct ata_channel *ch = request->device->channel;
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
struct ata_device *atadev = device_get_softc(request->dev);
int length;
ATA_DEBUG_RQ(request, "end transaction");
@ -297,9 +380,11 @@ ata_end_transaction(struct ata_request *request)
/* ATA PIO data transfer and control commands */
default:
/* XXX Doesn't handle the non-PIO case. */
/* on timeouts we have no data or anything so just return */
if (request->flags & ATA_R_TIMEOUT)
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
/* on control commands read back registers to the request struct */
if (request->flags & ATA_R_CONTROL) {
@ -307,21 +392,30 @@ ata_end_transaction(struct ata_request *request)
request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) |
(ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) |
(ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) |
((ATA_IDX_INB(ch, ATA_DRIVE) & 0x0f) << 24);
((ATA_IDX_INB(ch, ATA_DRIVE) & 0x0f) << 24);
}
/* if we got an error we are done with the HW */
if (request->status & ATA_S_ERROR) {
request->error = ATA_IDX_INB(ch, ATA_ERROR);
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
}
/* are we moving data ? */
if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
/* if read data get it */
if (request->flags & ATA_R_READ)
if (request->flags & ATA_R_READ) {
if (ata_wait(ch, atadev,
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
device_printf(request->dev, "timeout waiting for read DRQ");
request->result = EIO;
//return ATA_OP_FINISHED;
break;
}
ata_pio_read(request, request->transfersize);
}
/* update how far we've gotten */
request->donecount += request->transfersize;
@ -334,19 +428,17 @@ ata_end_transaction(struct ata_request *request)
min((request->bytecount - request->donecount),
request->transfersize);
/* clear interrupt seen flag as we need to wait again */
request->flags &= ~ATA_R_INTR_SEEN;
/* if data write command, output the data */
if (request->flags & ATA_R_WRITE) {
/* if we get an error here we are done with the HW */
if (ata_wait(request->device,
if (ata_wait(ch, atadev,
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
ata_prtdev(request->device,
"timeout waiting for write DRQ");
device_printf(request->dev,
"timeout waiting for write DRQ");
request->status = ATA_IDX_INB(ch, ATA_STATUS);
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
}
/* output data and return waiting for new interrupt */
@ -360,7 +452,8 @@ ata_end_transaction(struct ata_request *request)
}
}
/* done with HW */
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
/* ATA DMA data transfer commands */
case ATA_R_DMA:
@ -374,19 +467,25 @@ ata_end_transaction(struct ata_request *request)
request->error = ATA_IDX_INB(ch, ATA_ERROR);
else if (request->dmastat & ATA_BMSTAT_ERROR)
request->status |= ATA_S_ERROR;
else
else if (!(request->flags & ATA_R_TIMEOUT))
request->donecount = request->bytecount;
/* release SG list etc */
ch->dma->unload(ch);
/* done with HW */
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
/* ATAPI PIO commands */
case ATA_R_ATAPI:
length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8);
/* on timeouts we have no data or anything so just return */
if (request->flags & ATA_R_TIMEOUT)
//return ATA_OP_FINISHED;
break;
switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) |
(request->status & ATA_S_DRQ)) {
@ -395,12 +494,13 @@ ata_end_transaction(struct ata_request *request)
DELAY(10);
if (!(request->status & ATA_S_DRQ)) {
ata_prtdev(request->device, "command interrupt without DRQ\n");
device_printf(request->dev, "command interrupt without DRQ\n");
request->status = ATA_S_ERROR;
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
}
ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb,
(request->device->param->config &
(atadev->param.config &
ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8);
/* return wait for interrupt */
return ATA_OP_CONTINUES;
@ -408,10 +508,11 @@ ata_end_transaction(struct ata_request *request)
case ATAPI_P_WRITE:
if (request->flags & ATA_R_READ) {
request->status = ATA_S_ERROR;
ata_prtdev(request->device,
"%s trying to write on read buffer\n",
device_printf(request->dev,
"%s trying to write on read buffer\n",
ata_cmd2str(request));
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
}
ata_pio_write(request, length);
request->donecount += length;
@ -425,10 +526,11 @@ ata_end_transaction(struct ata_request *request)
case ATAPI_P_READ:
if (request->flags & ATA_R_WRITE) {
request->status = ATA_S_ERROR;
ata_prtdev(request->device,
"%s trying to read on write buffer\n",
device_printf(request->dev,
"%s trying to read on write buffer\n",
ata_cmd2str(request));
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
}
ata_pio_read(request, length);
request->donecount += length;
@ -440,9 +542,9 @@ ata_end_transaction(struct ata_request *request)
return ATA_OP_CONTINUES;
case ATAPI_P_DONEDRQ:
ata_prtdev(request->device,
"WARNING - %s DONEDRQ non conformant device\n",
ata_cmd2str(request));
device_printf(request->dev,
"WARNING - %s DONEDRQ non conformant device\n",
ata_cmd2str(request));
if (request->flags & ATA_R_READ) {
ata_pio_read(request, length);
request->donecount += length;
@ -459,15 +561,17 @@ ata_end_transaction(struct ata_request *request)
case ATAPI_P_DONE:
if (request->status & (ATA_S_ERROR | ATA_S_DWF))
request->error = ATA_IDX_INB(ch, ATA_ERROR);
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
default:
ata_prtdev(request->device, "unknown transfer phase\n");
device_printf(request->dev, "unknown transfer phase\n");
request->status = ATA_S_ERROR;
}
/* done with HW */
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
/* ATAPI DMA commands */
case ATA_R_ATAPI|ATA_R_DMA:
@ -481,39 +585,44 @@ ata_end_transaction(struct ata_request *request)
request->error = ATA_IDX_INB(ch, ATA_ERROR);
else if (request->dmastat & ATA_BMSTAT_ERROR)
request->status |= ATA_S_ERROR;
else
else if (!(request->flags & ATA_R_TIMEOUT))
request->donecount = request->bytecount;
/* release SG list etc */
ch->dma->unload(ch);
/* done with HW */
return ATA_OP_FINISHED;
//return ATA_OP_FINISHED;
break;
}
/* disable interrupt */
//ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT | ATA_A_IDS);
return ATA_OP_FINISHED;
}
/* must be called with ATA channel locked */
static void
ata_generic_reset(struct ata_channel *ch)
{
u_int8_t err = 0, lsb = 0, msb = 0, ostat0, ostat1;
u_int8_t stat0 = 0, stat1 = 0;
u_int8_t ostat0 = 0, stat0 = 0, ostat1 = 0, stat1 = 0;
u_int8_t err = 0, lsb = 0, msb = 0;
int mask = 0, timeout;
/* if DMA functionality present stop it */
if (ch->dma) {
if (ch->dma->stop)
ch->dma->stop(ch);
if (ch->dma->flags & ATA_DMA_LOADED)
ch->dma->unload(ch);
if (ch->dma->stop)
ch->dma->stop(ch);
if (ch->dma->flags & ATA_DMA_LOADED)
ch->dma->unload(ch);
}
/* reset host end of channel (if supported) */
if (ch->reset)
ch->reset(ch);
ATA_RESET(device_get_parent(ch->dev), ch->dev);
/* do we have any signs of ATA/ATAPI HW being present ? */
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
DELAY(10);
ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
@ -521,12 +630,11 @@ ata_generic_reset(struct ata_channel *ch)
mask |= 0x01;
}
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(10);
ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
/* in some setups we dont want to test for a slave */
if (!(ch->flags & ATA_NO_SLAVE)) {
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_SLAVE);
DELAY(10);
ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
stat1 = ATA_S_BUSY;
mask |= 0x02;
@ -534,8 +642,8 @@ ata_generic_reset(struct ata_channel *ch)
}
if (bootverbose)
ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n",
mask, ostat0, ostat1);
device_printf(ch->dev, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n",
mask, ostat0, ostat1);
/* if nothing showed up there is no need to get any further */
/* SOS is that too strong?, we just might loose devices here XXX */
@ -544,7 +652,7 @@ ata_generic_reset(struct ata_channel *ch)
return;
/* reset (both) devices on this channel */
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
DELAY(10);
ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
ata_udelay(10000);
@ -554,17 +662,19 @@ ata_generic_reset(struct ata_channel *ch)
/* wait for BUSY to go inactive */
for (timeout = 0; timeout < 310; timeout++) {
if (stat0 & ATA_S_BUSY) {
if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(10);
err = ATA_IDX_INB(ch, ATA_ERROR);
err = ATA_IDX_INB(ch, ATA_ERROR);
lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
stat0 = ATA_IDX_INB(ch, ATA_STATUS);
if (bootverbose)
ata_printf(ch, ATA_MASTER,
"stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
stat0, err, lsb, msb);
device_printf(ch->dev,
"stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
stat0, err, lsb, msb);
if (stat0 == err && lsb == err && msb == err && timeout > 10)
mask &= ~0x01;
if (!(stat0 & ATA_S_BUSY)) {
if ((err & 0x7f) == ATA_E_ILI) {
if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
@ -574,22 +684,25 @@ ata_generic_reset(struct ata_channel *ch)
ch->devices |= ATA_ATA_MASTER;
}
}
else if ((stat0 & 0x4f) && err == lsb && err == msb) {
else if ((stat0 & 0x0f) && err == lsb && err == msb) {
stat0 |= ATA_S_BUSY;
}
}
}
if (!((mask == 0x03) && (stat0 & ATA_S_BUSY)) && (stat1 & ATA_S_BUSY)) {
if ((mask & 0x02) && (stat1 & ATA_S_BUSY)) {
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(10);
err = ATA_IDX_INB(ch, ATA_ERROR);
err = ATA_IDX_INB(ch, ATA_ERROR);
lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
stat1 = ATA_IDX_INB(ch, ATA_STATUS);
if (bootverbose)
ata_printf(ch, ATA_SLAVE,
" stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
stat1, err, lsb, msb);
device_printf(ch->dev,
"stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
stat1, err, lsb, msb);
if (stat1 == err && lsb == err && msb == err && timeout > 10)
mask &= ~0x02;
if (!(stat1 & ATA_S_BUSY)) {
if ((err & 0x7f) == ATA_E_ILI) {
if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
@ -599,44 +712,39 @@ ata_generic_reset(struct ata_channel *ch)
ch->devices |= ATA_ATA_SLAVE;
}
}
else if ((stat1 & 0x4f) && err == lsb && err == msb) {
stat1 |= ATA_S_BUSY;
else if ((stat0 & 0x0f) && err == lsb && err == msb) {
stat0 |= ATA_S_BUSY;
}
}
}
if (mask == 0x01) /* wait for master only */
if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 5) ||
(stat0 == err && lsb == err && msb == err && timeout > 5))
if (mask == 0x00) /* nothing to wait for */
break;
if (mask == 0x01) /* wait for master only */
if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10))
break;
if (mask == 0x02) /* wait for slave only */
if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 5) ||
(stat1 == err && lsb == err && msb == err && timeout > 5))
if (mask == 0x02) /* wait for slave only */
if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 10))
break;
if (mask == 0x03) { /* wait for both master & slave */
if (mask == 0x03) { /* wait for both master & slave */
if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
break;
if ((stat0 == 0xff && timeout > 5) ||
(stat0 == err && lsb == err && msb == err && timeout > 5))
if ((stat0 == 0xff) && (timeout > 20))
mask &= ~0x01;
if ((stat1 == 0xff && timeout > 5) ||
(stat1 == err && lsb == err && msb == err && timeout > 5))
if ((stat1 == 0xff) && (timeout > 20))
mask &= ~0x02;
}
if (mask == 0 && !(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
break;
ata_udelay(100000);
}
if (bootverbose)
ata_printf(ch, -1,
"reset tp2 stat0=%02x stat1=%02x devices=0x%b\n",
stat0, stat1, ch->devices,
"\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
device_printf(ch->dev, "reset tp2 stat0=%02x stat1=%02x devices=0x%b\n",
stat0, stat1, ch->devices,
"\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
}
static int
ata_wait(struct ata_device *atadev, u_int8_t mask)
ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask)
{
u_int8_t status;
int timeout = 0;
@ -645,21 +753,19 @@ ata_wait(struct ata_device *atadev, u_int8_t mask)
/* wait 5 seconds for device to get !BUSY */
while (timeout < 5000000) {
status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
status = ATA_IDX_INB(ch, ATA_ALTSTAT);
/* if drive fails status, reselect the drive just to be sure */
/* if drive fails status, reselect the drive and try again */
if (status == 0xff) {
ata_prtdev(atadev, "WARNING no status, reselecting device\n");
ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
DELAY(10);
status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
if (status == 0xff)
return -1;
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit);
timeout += 1000;
DELAY(1000);
continue;
}
/* are we done ? */
if (!(status & ATA_S_BUSY))
break;
break;
if (timeout > 1000) {
timeout += 1000;
@ -669,50 +775,46 @@ ata_wait(struct ata_device *atadev, u_int8_t mask)
timeout += 10;
DELAY(10);
}
}
if (timeout >= 5000000)
return -1;
if (!mask)
return (status & ATA_S_ERROR);
}
if (timeout >= 5000000)
return -2;
if (!mask)
return (status & ATA_S_ERROR);
DELAY(1);
/* wait 50 msec for bits wanted */
/* wait 50 msec for bits wanted */
timeout = 5000;
while (timeout--) {
status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
while (timeout--) {
status = ATA_IDX_INB(ch, ATA_ALTSTAT);
if ((status & mask) == mask)
return (status & ATA_S_ERROR);
DELAY (10);
}
return -1;
return (status & ATA_S_ERROR);
DELAY(10);
}
return -3;
}
int
ata_generic_command(struct ata_device *atadev, u_int8_t command,
u_int64_t lba, u_int16_t count, u_int16_t feature)
u_int64_t lba, u_int16_t count, u_int16_t feature)
{
if (atadebug)
ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, "
"lba=%jd, count=%d, feature=%d\n",
rman_get_start(atadev->channel->r_io[ATA_DATA].res),
command, (intmax_t)lba, count, feature);
struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev));
/* select device */
ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit);
/* ready to issue command ? */
if (ata_wait(atadev, 0) < 0) {
ata_prtdev(atadev, "timeout sending command=%02x\n", command);
if (ata_wait(ch, atadev, 0) < 0) {
device_printf(atadev->dev, "timeout sending command=%02x\n", command);
return -1;
}
/* enable interrupt */
ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT);
ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT);
/* only use 48bit addressing if needed (avoid bugs and overhead) */
if ((lba >= ATA_MAX_28BIT_LBA || count > 256) && atadev->param &&
atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) {
if ((lba >= ATA_MAX_28BIT_LBA || count > 256) &&
atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) {
/* translate command into 48bit version */
switch (command) {
@ -735,39 +837,54 @@ ata_generic_command(struct ata_device *atadev, u_int8_t command,
case ATA_FLUSHCACHE:
command = ATA_FLUSHCACHE48; break;
default:
ata_prtdev(atadev, "can't translate cmd to 48bit version\n");
device_printf(atadev->dev,"can't translate cmd to 48bit version\n");
return -1;
}
ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit);
atadev->channel->flags |= ATA_48BIT_ACTIVE;
ATA_IDX_OUTB(ch, ATA_FEATURE, (feature>>8) & 0xff);
ATA_IDX_OUTB(ch, ATA_FEATURE, feature & 0xff);
ATA_IDX_OUTB(ch, ATA_COUNT, (count>>8) & 0xff);
ATA_IDX_OUTB(ch, ATA_COUNT, count & 0xff);
ATA_IDX_OUTB(ch, ATA_SECTOR, (lba>>24) & 0xff);
ATA_IDX_OUTB(ch, ATA_SECTOR, lba & 0xff);
ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba>>32) & 0xff);
ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba>>8) & 0xff);
ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba>>40) & 0xff);
ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba>>16) & 0xff);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
ch->flags |= ATA_48BIT_ACTIVE;
}
else {
ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature);
ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count);
ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
if (atadev->flags & ATA_D_USE_CHS)
ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf));
else
ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
ATA_D_IBM | ATA_D_LBA | atadev->unit|((lba>>24)&0xf));
atadev->channel->flags &= ~ATA_48BIT_ACTIVE;
ATA_IDX_OUTB(ch, ATA_FEATURE, feature);
ATA_IDX_OUTB(ch, ATA_COUNT, count);
if (atadev->flags & ATA_D_USE_CHS) {
int heads, sectors;
if (atadev->param.atavalid & ATA_FLAG_54_58) {
heads = atadev->param.current_heads;
sectors = atadev->param.current_sectors;
}
else {
heads = atadev->param.heads;
sectors = atadev->param.sectors;
}
ATA_IDX_OUTB(ch, ATA_SECTOR, (lba % sectors) + 1);
ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba / (sectors * heads)));
ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba / (sectors * heads)) >> 8);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit |
(((lba % (sectors * heads)) / sectors) & 0xf));
}
else {
ATA_IDX_OUTB(ch, ATA_SECTOR, lba & 0xff);
ATA_IDX_OUTB(ch, ATA_CYL_LSB, (lba>>8) & 0xff);
ATA_IDX_OUTB(ch, ATA_CYL_MSB, (lba>>16) & 0xff);
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit |
((lba>>24) & 0x0f));
}
ch->flags &= ~ATA_48BIT_ACTIVE;
}
/* issue command to controller */
ATA_IDX_OUTB(atadev->channel, ATA_CMD, command);
ATA_IDX_OUTB(ch, ATA_CMD, command);
return 0;
}
@ -775,8 +892,8 @@ ata_generic_command(struct ata_device *atadev, u_int8_t command,
static void
ata_pio_read(struct ata_request *request, int length)
{
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
int size = min(request->transfersize, length);
struct ata_channel *ch = request->device->channel;
int resid;
if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
@ -789,7 +906,7 @@ ata_pio_read(struct ata_request *request, int length)
size / sizeof(int32_t));
if (request->transfersize < length) {
ata_prtdev(request->device, "WARNING - %s read data overrun %d>%d\n",
device_printf(request->dev, "WARNING - %s read data overrun %d>%d\n",
ata_cmd2str(request), length, request->transfersize);
for (resid = request->transfersize; resid < length;
resid += sizeof(int16_t))
@ -800,8 +917,8 @@ ata_pio_read(struct ata_request *request, int length)
static void
ata_pio_write(struct ata_request *request, int length)
{
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
int size = min(request->transfersize, length);
struct ata_channel *ch = request->device->channel;
int resid;
if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
@ -814,10 +931,54 @@ ata_pio_write(struct ata_request *request, int length)
size / sizeof(int32_t));
if (request->transfersize < length) {
ata_prtdev(request->device, "WARNING - %s write data underrun %d>%d\n",
device_printf(request->dev, "WARNING - %s write data underrun %d>%d\n",
ata_cmd2str(request), length, request->transfersize);
for (resid = request->transfersize; resid < length;
resid += sizeof(int16_t))
ATA_IDX_OUTW(ch, ATA_DATA, 0);
}
}
static void
bswap(int8_t *buf, int len)
{
u_int16_t *ptr = (u_int16_t*)(buf + len);
while (--ptr >= (u_int16_t*)buf)
*ptr = ntohs(*ptr);
}
static void
btrim(int8_t *buf, int len)
{
int8_t *ptr;
for (ptr = buf; ptr < buf+len; ++ptr)
if (!*ptr || *ptr == '_')
*ptr = ' ';
for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
*ptr = 0;
}
static void
bpack(int8_t *src, int8_t *dst, int len)
{
int i, j, blank;
for (i = j = blank = 0 ; i < len; i++) {
if (blank && src[i] == ' ') continue;
if (blank && src[i] != ' ') {
dst[j++] = src[i];
blank = 0;
continue;
}
if (src[i] == ' ') {
blank = 1;
if (i == 0)
continue;
}
dst[j++] = src[i];
}
if (j < len)
dst[j] = 0x00;
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/ata.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/sema.h>
@ -50,17 +51,17 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-pci.h>
#include <ata_if.h>
/* local vars */
static MALLOC_DEFINE(M_ATAPCI, "ATA PCI", "ATA driver PCI");
/* misc defines */
#define IOMASK 0xfffffffc
#define IOMASK 0xfffffffc
/* prototypes */
static int ata_pci_allocate(device_t, struct ata_channel *);
static int ata_pci_allocate(device_t dev, struct ata_channel *ch);
static void ata_pci_dmainit(struct ata_channel *);
static int ata_pci_locknoop(struct ata_channel *, int);
int
ata_legacy(device_t dev)
@ -71,7 +72,7 @@ ata_legacy(device_t dev)
(PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)));
}
static int
int
ata_pci_probe(device_t dev)
{
if (pci_get_class(dev) != PCIC_STORAGE)
@ -164,7 +165,7 @@ ata_pci_probe(device_t dev)
return ENXIO;
}
static int
int
ata_pci_attach(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
@ -178,7 +179,7 @@ ata_pci_attach(device_t dev)
ctlr->channels = 1;
ctlr->allocate = ata_pci_allocate;
ctlr->dmainit = ata_pci_dmainit;
ctlr->locking = ata_pci_locknoop;
ctlr->dev = dev;
/* if needed try to enable busmastering */
cmd = pci_read_config(dev, PCIR_COMMAND, 2);
@ -209,24 +210,24 @@ ata_pci_attach(device_t dev)
}
device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 2));
}
return bus_generic_attach(dev);
bus_generic_attach(dev);
return 0;
}
static int
int
ata_pci_detach(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
struct ata_channel *ch;
int unit;
device_t *children;
int nchildren, i;
/* mark HW as gone, we dont want to issue commands to HW no longer there */
for (unit = 0; unit < ctlr->channels; unit++) {
if ((ch = ctlr->interrupt[unit].argument))
ch->flags |= ATA_HWGONE;
/* detach & delete all children */
if (!device_get_children(dev, &children, &nchildren)) {
for (i = 0; i < nchildren; i++)
device_delete_child(dev, children[i]);
free(children, M_TEMP);
}
bus_generic_detach(dev);
if (ctlr->r_irq) {
bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle);
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ctlr->r_irq);
@ -239,19 +240,7 @@ ata_pci_detach(device_t dev)
return 0;
}
static int
ata_pci_print_child(device_t dev, device_t child)
{
struct ata_channel *ch = device_get_softc(child);
int retval = 0;
retval += bus_print_child_header(dev, child);
retval += printf(": channel #%d", ch->unit);
retval += bus_print_child_footer(dev, child);
return retval;
}
static struct resource *
struct resource *
ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
@ -307,7 +296,7 @@ ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
return 0;
}
static int
int
ata_pci_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *r)
{
@ -348,7 +337,7 @@ ata_pci_release_resource(device_t dev, device_t child, int type, int rid,
return EINVAL;
}
static int
int
ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
int flags, driver_intr_t *function, void *argument,
void **cookiep)
@ -373,7 +362,7 @@ ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
}
}
static int
int
ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
void *cookie)
{
@ -435,12 +424,46 @@ ata_pci_allocate(device_t dev, struct ata_channel *ch)
return 0;
}
static void
ata_pci_setmode(device_t parent, device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(parent);
struct ata_device *atadev = device_get_softc(dev);
int mode = atadev->mode;
ctlr->setmode(atadev, ATA_PIO_MAX);
if (mode >= ATA_DMA)
ctlr->setmode(atadev, mode);
}
static int
ata_pci_locking(device_t parent, device_t dev, int mode)
{
struct ata_pci_controller *ctlr = device_get_softc(parent);
struct ata_channel *ch = device_get_softc(dev);
if (ctlr->locking)
return ctlr->locking(ch, mode);
else
return ch->unit;
}
static void
ata_pci_reset(device_t parent, device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(parent);
struct ata_channel *ch = device_get_softc(dev);
if (ctlr->reset)
ctlr->reset(ch);
}
static int
ata_pci_dmastart(struct ata_channel *ch)
{
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
(ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus);
ch->dma->flags |= ATA_DMA_ACTIVE;
ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
(ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) |
@ -472,41 +495,41 @@ ata_pci_dmainit(struct ata_channel *ch)
}
}
static int
ata_pci_locknoop(struct ata_channel *ch, int flags)
{
return ch->unit;
}
static device_method_t ata_pci_methods[] = {
/* device interface */
DEVMETHOD(device_probe, ata_pci_probe),
DEVMETHOD(device_attach, ata_pci_attach),
DEVMETHOD(device_detach, ata_pci_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
DEVMETHOD(device_probe, ata_pci_probe),
DEVMETHOD(device_attach, ata_pci_attach),
DEVMETHOD(device_detach, ata_pci_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
/* bus methods */
DEVMETHOD(bus_print_child, ata_pci_print_child),
DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
DEVMETHOD(bus_release_resource, ata_pci_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
DEVMETHOD(bus_release_resource, ata_pci_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
/* ATA methods */
DEVMETHOD(ata_setmode, ata_pci_setmode),
DEVMETHOD(ata_locking, ata_pci_locking),
DEVMETHOD(ata_reset, ata_pci_reset),
{ 0, 0 }
};
devclass_t atapci_devclass;
static driver_t ata_pci_driver = {
"atapci",
ata_pci_methods,
sizeof(struct ata_pci_controller),
};
static devclass_t ata_pci_devclass;
DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0);
DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0);
MODULE_VERSION(atapci, 1);
MODULE_DEPEND(atapci, ata, 1, 1, 1);
static int
ata_channel_probe(device_t dev)
@ -514,6 +537,7 @@ ata_channel_probe(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
device_t *children;
int count, i;
char buffer[32];
/* take care of green memory */
bzero(ch, sizeof(struct ata_channel));
@ -526,6 +550,9 @@ ata_channel_probe(device_t dev)
}
free(children, M_TEMP);
sprintf(buffer, "ATA channel %d", ch->unit);
device_set_desc_copy(dev, buffer);
return ata_probe(dev);
}
@ -536,11 +563,6 @@ ata_channel_attach(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
int error;
ch->device[MASTER].setmode = ctlr->setmode;
ch->device[SLAVE].setmode = ctlr->setmode;
ch->locking = ctlr->locking;
ch->reset = ctlr->reset;
if (ctlr->r_res1)
ctlr->dmainit(ch);
if (ch->dma)
@ -569,15 +591,16 @@ ata_channel_detach(device_t dev)
static device_method_t ata_channel_methods[] = {
/* device interface */
DEVMETHOD(device_probe, ata_channel_probe),
DEVMETHOD(device_attach, ata_channel_attach),
DEVMETHOD(device_detach, ata_channel_detach),
DEVMETHOD(device_suspend, ata_suspend),
DEVMETHOD(device_resume, ata_resume),
DEVMETHOD(device_probe, ata_channel_probe),
DEVMETHOD(device_attach, ata_channel_attach),
DEVMETHOD(device_detach, ata_channel_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
{ 0, 0 }
};
static driver_t ata_channel_driver = {
driver_t ata_channel_driver = {
"ata",
ata_channel_methods,
sizeof(struct ata_channel),

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2003, 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 2003 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,306 +30,321 @@
/* structure holding chipset config info */
struct ata_chip_id {
u_int32_t chipid;
u_int8_t chiprev;
int cfg1;
int cfg2;
u_int8_t max_dma;
char *text;
u_int32_t chipid;
u_int8_t chiprev;
int cfg1;
int cfg2;
u_int8_t max_dma;
char *text;
};
/* structure describing a PCI ATA controller */
struct ata_pci_controller {
int r_type1;
int r_rid1;
struct resource *r_res1;
int r_type2;
int r_rid2;
struct resource *r_res2;
struct resource *r_irq;
void *handle;
struct ata_chip_id *chip;
int channels;
int (*chipinit)(device_t);
int (*allocate)(device_t, struct ata_channel *);
void (*reset)(struct ata_channel *);
void (*dmainit)(struct ata_channel *);
void (*setmode)(struct ata_device *, int);
int (*locking)(struct ata_channel *, int);
device_t dev;
int r_type1;
int r_rid1;
struct resource *r_res1;
int r_type2;
int r_rid2;
struct resource *r_res2;
struct resource *r_irq;
void *handle;
struct ata_chip_id *chip;
int channels;
int (*chipinit)(device_t);
int (*allocate)(device_t, struct ata_channel *);
int (*locking)(struct ata_channel *, int);
void (*reset)(struct ata_channel *);
void (*dmainit)(struct ata_channel *);
void (*setmode)(struct ata_device *, int);
struct {
void (*function)(void *);
void *argument;
} interrupt[8]; /* SOS max ch# for now XXX */
void *driver;
void (*function)(void *);
void *argument;
} interrupt[8]; /* SOS max ch# for now XXX */
};
/* structure for SATA connection update hotplug/hotswap support */
struct ata_connect_task {
struct task task;
device_t dev;
int action;
#define ATA_C_ATTACH 1
#define ATA_C_DETACH 2
};
/* defines for known chipset PCI id's */
#define ATA_ACARD_ID 0x1191
#define ATA_ATP850 0x00021191
#define ATA_ATP850A 0x00041191
#define ATA_ATP850R 0x00051191
#define ATA_ATP860A 0x00061191
#define ATA_ATP860R 0x00071191
#define ATA_ATP865A 0x00081191
#define ATA_ATP865R 0x00091191
#define ATA_ACARD_ID 0x1191
#define ATA_ATP850 0x00021191
#define ATA_ATP850A 0x00041191
#define ATA_ATP850R 0x00051191
#define ATA_ATP860A 0x00061191
#define ATA_ATP860R 0x00071191
#define ATA_ATP865A 0x00081191
#define ATA_ATP865R 0x00091191
#define ATA_AMD_ID 0x1022
#define ATA_AMD755 0x74011022
#define ATA_AMD756 0x74091022
#define ATA_AMD766 0x74111022
#define ATA_AMD768 0x74411022
#define ATA_AMD8111 0x74691022
#define ATA_AMD_ID 0x1022
#define ATA_AMD755 0x74011022
#define ATA_AMD756 0x74091022
#define ATA_AMD766 0x74111022
#define ATA_AMD768 0x74411022
#define ATA_AMD8111 0x74691022
#define ATA_ACER_LABS_ID 0x10b9
#define ATA_ALI_5229 0x522910b9
#define ATA_ACER_LABS_ID 0x10b9
#define ATA_ALI_5229 0x522910b9
#define ATA_CENATEK_ID 0x16ca
#define ATA_CENATEK_ROCKET 0x000116ca
#define ATA_CENATEK_ID 0x16ca
#define ATA_CENATEK_ROCKET 0x000116ca
#define ATA_CYRIX_ID 0x1078
#define ATA_CYRIX_5530 0x01021078
#define ATA_CYRIX_ID 0x1078
#define ATA_CYRIX_5530 0x01021078
#define ATA_CYPRESS_ID 0x1080
#define ATA_CYPRESS_82C693 0xc6931080
#define ATA_CYPRESS_ID 0x1080
#define ATA_CYPRESS_82C693 0xc6931080
#define ATA_DEC_21150 0x00221011
#define ATA_DEC_21150_1 0x00231011
#define ATA_DEC_21150 0x00221011
#define ATA_DEC_21150_1 0x00231011
#define ATA_HIGHPOINT_ID 0x1103
#define ATA_HPT366 0x00041103
#define ATA_HPT372 0x00051103
#define ATA_HPT302 0x00061103
#define ATA_HPT371 0x00071103
#define ATA_HPT374 0x00081103
#define ATA_HIGHPOINT_ID 0x1103
#define ATA_HPT366 0x00041103
#define ATA_HPT372 0x00051103
#define ATA_HPT302 0x00061103
#define ATA_HPT371 0x00071103
#define ATA_HPT374 0x00081103
#define ATA_INTEL_ID 0x8086
#define ATA_I960RM 0x09628086
#define ATA_I82371FB 0x12308086
#define ATA_I82371SB 0x70108086
#define ATA_I82371AB 0x71118086
#define ATA_I82443MX 0x71998086
#define ATA_I82451NX 0x84ca8086
#define ATA_I82372FB 0x76018086
#define ATA_I82801AB 0x24218086
#define ATA_I82801AA 0x24118086
#define ATA_I82801BA 0x244a8086
#define ATA_I82801BA_1 0x244b8086
#define ATA_I82801CA 0x248a8086
#define ATA_I82801CA_1 0x248b8086
#define ATA_I82801DB 0x24cb8086
#define ATA_I82801DB_1 0x24ca8086
#define ATA_I82801EB 0x24db8086
#define ATA_I82801EB_S1 0x24d18086
#define ATA_I82801EB_R1 0x24df8086
#define ATA_I6300ESB 0x25a28086
#define ATA_I6300ESB_S1 0x25a38086
#define ATA_I6300ESB_R1 0x25b08086
#define ATA_I82801FB 0x266f8086
#define ATA_I82801FB_S1 0x26518086
#define ATA_I82801FB_R1 0x26528086
#define ATA_INTEL_ID 0x8086
#define ATA_I960RM 0x09628086
#define ATA_I82371FB 0x12308086
#define ATA_I82371SB 0x70108086
#define ATA_I82371AB 0x71118086
#define ATA_I82443MX 0x71998086
#define ATA_I82451NX 0x84ca8086
#define ATA_I82372FB 0x76018086
#define ATA_I82801AB 0x24218086
#define ATA_I82801AA 0x24118086
#define ATA_I82801BA 0x244a8086
#define ATA_I82801BA_1 0x244b8086
#define ATA_I82801CA 0x248a8086
#define ATA_I82801CA_1 0x248b8086
#define ATA_I82801DB 0x24cb8086
#define ATA_I82801DB_1 0x24ca8086
#define ATA_I82801EB 0x24db8086
#define ATA_I82801EB_S1 0x24d18086
#define ATA_I82801EB_R1 0x24df8086
#define ATA_I6300ESB 0x25a28086
#define ATA_I6300ESB_S1 0x25a38086
#define ATA_I6300ESB_R1 0x25b08086
#define ATA_I82801FB 0x266f8086
#define ATA_I82801FB_S1 0x26518086
#define ATA_I82801FB_R1 0x26528086
#define ATA_ITE_ID 0x1283
#define ATA_IT8212F 0x82121283
#define ATA_MICRON_ID 0x1042
#define ATA_MICRON_RZ1000 0x10001042
#define ATA_MICRON_RZ1001 0x10011042
#define ATA_ITE_ID 0x1283
#define ATA_IT8212F 0x82121283
#define ATA_NATIONAL_ID 0x100b
#define ATA_SC1100 0x0502100b
#define ATA_MICRON_ID 0x1042
#define ATA_MICRON_RZ1000 0x10001042
#define ATA_MICRON_RZ1001 0x10011042
#define ATA_NVIDIA_ID 0x10de
#define ATA_NFORCE1 0x01bc10de
#define ATA_NFORCE2 0x006510de
#define ATA_NFORCE2_MCP 0x008510de
#define ATA_NFORCE3 0x00d510de
#define ATA_NFORCE3_PRO 0x00e510de
#define ATA_NFORCE3_PRO_S1 0x00e310de
#define ATA_NFORCE3_PRO_S2 0x00ee10de
#define ATA_NFORCE3_MCP 0x003510de
#define ATA_NFORCE3_MCP_S1 0x003610de
#define ATA_NFORCE3_MCP_S2 0x003e10de
#define ATA_NFORCE4 0x005310de
#define ATA_NFORCE4_S1 0x005410de
#define ATA_NFORCE4_S2 0x005510de
#define ATA_NATIONAL_ID 0x100b
#define ATA_SC1100 0x0502100b
#define ATA_NVIDIA_ID 0x10de
#define ATA_NFORCE1 0x01bc10de
#define ATA_NFORCE2 0x006510de
#define ATA_NFORCE2_MCP 0x008510de
#define ATA_NFORCE3 0x00d510de
#define ATA_NFORCE3_PRO 0x00e510de
#define ATA_NFORCE3_PRO_S1 0x00e310de
#define ATA_NFORCE3_PRO_S2 0x00ee10de
#define ATA_NFORCE3_MCP 0x003510de
#define ATA_NFORCE3_MCP_S1 0x003610de
#define ATA_NFORCE3_MCP_S2 0x003e10de
#define ATA_NFORCE4 0x005310de
#define ATA_NFORCE4_S1 0x005410de
#define ATA_NFORCE4_S2 0x005510de
#define ATA_PROMISE_ID 0x105a
#define ATA_PDC20246 0x4d33105a
#define ATA_PDC20262 0x4d38105a
#define ATA_PDC20263 0x0d38105a
#define ATA_PDC20265 0x0d30105a
#define ATA_PDC20267 0x4d30105a
#define ATA_PDC20268 0x4d68105a
#define ATA_PDC20269 0x4d69105a
#define ATA_PDC20270 0x6268105a
#define ATA_PDC20271 0x6269105a
#define ATA_PDC20275 0x1275105a
#define ATA_PDC20276 0x5275105a
#define ATA_PDC20277 0x7275105a
#define ATA_PDC20318 0x3318105a
#define ATA_PDC20319 0x3319105a
#define ATA_PDC20371 0x3371105a
#define ATA_PDC20375 0x3375105a
#define ATA_PDC20376 0x3376105a
#define ATA_PDC20377 0x3377105a
#define ATA_PDC20378 0x3373105a
#define ATA_PDC20379 0x3372105a
#define ATA_PDC20571 0x3571105a
#define ATA_PDC20575 0x3d75105a
#define ATA_PDC20579 0x3574105a
#define ATA_PDC20580 0x3570105a
#define ATA_PDC40518 0x3d18105a
#define ATA_PDC20617 0x6617105a
#define ATA_PDC20618 0x6626105a
#define ATA_PDC20619 0x6629105a
#define ATA_PDC20620 0x6620105a
#define ATA_PDC20621 0x6621105a
#define ATA_PDC20622 0x6622105a
#define ATA_PROMISE_ID 0x105a
#define ATA_PDC20246 0x4d33105a
#define ATA_PDC20262 0x4d38105a
#define ATA_PDC20263 0x0d38105a
#define ATA_PDC20265 0x0d30105a
#define ATA_PDC20267 0x4d30105a
#define ATA_PDC20268 0x4d68105a
#define ATA_PDC20269 0x4d69105a
#define ATA_PDC20270 0x6268105a
#define ATA_PDC20271 0x6269105a
#define ATA_PDC20275 0x1275105a
#define ATA_PDC20276 0x5275105a
#define ATA_PDC20277 0x7275105a
#define ATA_PDC20318 0x3318105a
#define ATA_PDC20319 0x3319105a
#define ATA_PDC20371 0x3371105a
#define ATA_PDC20375 0x3375105a
#define ATA_PDC20376 0x3376105a
#define ATA_PDC20377 0x3377105a
#define ATA_PDC20378 0x3373105a
#define ATA_PDC20379 0x3372105a
#define ATA_PDC20571 0x3571105a
#define ATA_PDC20575 0x3d75105a
#define ATA_PDC20579 0x3574105a
#define ATA_PDC20580 0x3570105a
#define ATA_PDC40518 0x3d18105a
#define ATA_PDC20617 0x6617105a
#define ATA_PDC20618 0x6626105a
#define ATA_PDC20619 0x6629105a
#define ATA_PDC20620 0x6620105a
#define ATA_PDC20621 0x6621105a
#define ATA_PDC20622 0x6622105a
#define ATA_SERVERWORKS_ID 0x1166
#define ATA_ROSB4_ISA 0x02001166
#define ATA_ROSB4 0x02111166
#define ATA_CSB5 0x02121166
#define ATA_CSB6 0x02131166
#define ATA_CSB6_1 0x02171166
#define ATA_SERVERWORKS_ID 0x1166
#define ATA_ROSB4_ISA 0x02001166
#define ATA_ROSB4 0x02111166
#define ATA_CSB5 0x02121166
#define ATA_CSB6 0x02131166
#define ATA_CSB6_1 0x02171166
#define ATA_SILICON_IMAGE_ID 0x1095
#define ATA_SII3114 0x31141095
#define ATA_SII3512 0x35121095
#define ATA_SII3112 0x31121095
#define ATA_SII3112_1 0x02401095
#define ATA_SII0680 0x06801095
#define ATA_CMD646 0x06461095
#define ATA_CMD648 0x06481095
#define ATA_CMD649 0x06491095
#define ATA_SILICON_IMAGE_ID 0x1095
#define ATA_SII3114 0x31141095
#define ATA_SII3512 0x35121095
#define ATA_SII3112 0x31121095
#define ATA_SII3112_1 0x02401095
#define ATA_SII0680 0x06801095
#define ATA_CMD646 0x06461095
#define ATA_CMD648 0x06481095
#define ATA_CMD649 0x06491095
#define ATA_SIS_ID 0x1039
#define ATA_SISSOUTH 0x00081039
#define ATA_SIS5511 0x55111039
#define ATA_SIS5513 0x55131039
#define ATA_SIS5517 0x55171039
#define ATA_SIS5518 0x55181039
#define ATA_SIS5571 0x55711039
#define ATA_SIS5591 0x55911039
#define ATA_SIS5596 0x55961039
#define ATA_SIS5597 0x55971039
#define ATA_SIS5598 0x55981039
#define ATA_SIS5600 0x56001039
#define ATA_SIS530 0x05301039
#define ATA_SIS540 0x05401039
#define ATA_SIS550 0x05501039
#define ATA_SIS620 0x06201039
#define ATA_SIS630 0x06301039
#define ATA_SIS635 0x06351039
#define ATA_SIS633 0x06331039
#define ATA_SIS640 0x06401039
#define ATA_SIS645 0x06451039
#define ATA_SIS646 0x06461039
#define ATA_SIS648 0x06481039
#define ATA_SIS650 0x06501039
#define ATA_SIS651 0x06511039
#define ATA_SIS652 0x06521039
#define ATA_SIS655 0x06551039
#define ATA_SIS658 0x06581039
#define ATA_SIS661 0x06611039
#define ATA_SIS730 0x07301039
#define ATA_SIS733 0x07331039
#define ATA_SIS735 0x07351039
#define ATA_SIS740 0x07401039
#define ATA_SIS745 0x07451039
#define ATA_SIS746 0x07461039
#define ATA_SIS748 0x07481039
#define ATA_SIS750 0x07501039
#define ATA_SIS751 0x07511039
#define ATA_SIS752 0x07521039
#define ATA_SIS755 0x07551039
#define ATA_SIS961 0x09611039
#define ATA_SIS962 0x09621039
#define ATA_SIS963 0x09631039
#define ATA_SIS964 0x09641039
#define ATA_SIS964_S 0x01801039
#define ATA_SIS_ID 0x1039
#define ATA_SISSOUTH 0x00081039
#define ATA_SIS5511 0x55111039
#define ATA_SIS5513 0x55131039
#define ATA_SIS5517 0x55171039
#define ATA_SIS5518 0x55181039
#define ATA_SIS5571 0x55711039
#define ATA_SIS5591 0x55911039
#define ATA_SIS5596 0x55961039
#define ATA_SIS5597 0x55971039
#define ATA_SIS5598 0x55981039
#define ATA_SIS5600 0x56001039
#define ATA_SIS530 0x05301039
#define ATA_SIS540 0x05401039
#define ATA_SIS550 0x05501039
#define ATA_SIS620 0x06201039
#define ATA_SIS630 0x06301039
#define ATA_SIS635 0x06351039
#define ATA_SIS633 0x06331039
#define ATA_SIS640 0x06401039
#define ATA_SIS645 0x06451039
#define ATA_SIS646 0x06461039
#define ATA_SIS648 0x06481039
#define ATA_SIS650 0x06501039
#define ATA_SIS651 0x06511039
#define ATA_SIS652 0x06521039
#define ATA_SIS655 0x06551039
#define ATA_SIS658 0x06581039
#define ATA_SIS661 0x06611039
#define ATA_SIS730 0x07301039
#define ATA_SIS733 0x07331039
#define ATA_SIS735 0x07351039
#define ATA_SIS740 0x07401039
#define ATA_SIS745 0x07451039
#define ATA_SIS746 0x07461039
#define ATA_SIS748 0x07481039
#define ATA_SIS750 0x07501039
#define ATA_SIS751 0x07511039
#define ATA_SIS752 0x07521039
#define ATA_SIS755 0x07551039
#define ATA_SIS961 0x09611039
#define ATA_SIS962 0x09621039
#define ATA_SIS963 0x09631039
#define ATA_SIS964 0x09641039
#define ATA_SIS965 0x09641039
#define ATA_SIS180 0x01801039
#define ATA_SIS181 0x01811039
#define ATA_VIA_ID 0x1106
#define ATA_VIA82C571 0x05711106
#define ATA_VIA82C586 0x05861106
#define ATA_VIA82C596 0x05961106
#define ATA_VIA82C686 0x06861106
#define ATA_VIA8231 0x82311106
#define ATA_VIA8233 0x30741106
#define ATA_VIA8233A 0x31471106
#define ATA_VIA8233C 0x31091106
#define ATA_VIA8235 0x31771106
#define ATA_VIA8237 0x32271106
#define ATA_VIA8361 0x31121106
#define ATA_VIA8363 0x03051106
#define ATA_VIA8371 0x03911106
#define ATA_VIA8662 0x31021106
#define ATA_VIA6410 0x31641106
#define ATA_VIA6420 0x31491106
#define ATA_VIA_ID 0x1106
#define ATA_VIA82C571 0x05711106
#define ATA_VIA82C586 0x05861106
#define ATA_VIA82C596 0x05961106
#define ATA_VIA82C686 0x06861106
#define ATA_VIA8231 0x82311106
#define ATA_VIA8233 0x30741106
#define ATA_VIA8233A 0x31471106
#define ATA_VIA8233C 0x31091106
#define ATA_VIA8235 0x31771106
#define ATA_VIA8237 0x32271106
#define ATA_VIA8361 0x31121106
#define ATA_VIA8363 0x03051106
#define ATA_VIA8371 0x03911106
#define ATA_VIA8662 0x31021106
#define ATA_VIA6410 0x31641106
#define ATA_VIA6420 0x31491106
/* chipset setup related defines */
#define ATPOLD 1
#define ATPOLD 1
#define ALIOLD 0x01
#define ALINEW 0x02
#define ALIOLD 0x01
#define ALINEW 0x02
#define HPT366 0
#define HPT370 1
#define HPT372 2
#define HPT374 3
#define HPTOLD 0x01
#define HPT366 0
#define HPT370 1
#define HPT372 2
#define HPT374 3
#define HPTOLD 0x01
#define PROLD 0
#define PRNEW 1
#define PRTX 2
#define PRMIO 3
#define PRTX4 0x01
#define PRSX4X 0x02
#define PRSX6K 0x04
#define PRPATA 0x08
#define PRCMBO 0x10
#define PRCMBO2 0x20
#define PRSATA 0x40
#define PRSATA2 0x80
#define PROLD 0
#define PRNEW 1
#define PRTX 2
#define PRMIO 3
#define PRTX4 0x01
#define PRSX4X 0x02
#define PRSX6K 0x04
#define PRPATA 0x08
#define PRCMBO 0x10
#define PRCMBO2 0x20
#define PRSATA 0x40
#define PRSATA2 0x80
#define SWKS33 0
#define SWKS66 1
#define SWKS100 2
#define SWKS33 0
#define SWKS66 1
#define SWKS100 2
#define SIIMEMIO 1
#define SIIINTR 0x01
#define SIISETCLK 0x02
#define SIIBUG 0x04
#define SII4CH 0x08
#define SIIMEMIO 1
#define SIIINTR 0x01
#define SIISETCLK 0x02
#define SIIBUG 0x04
#define SII4CH 0x08
#define SIS_SOUTH 1
#define SISSATA 2
#define SIS133NEW 3
#define SIS133OLD 4
#define SIS100NEW 5
#define SIS100OLD 6
#define SIS66 7
#define SIS33 8
#define SIS_SOUTH 1
#define SISSATA 2
#define SIS133NEW 3
#define SIS133OLD 4
#define SIS100NEW 5
#define SIS100OLD 6
#define SIS66 7
#define SIS33 8
#define VIA33 0
#define VIA66 1
#define VIA100 2
#define VIA133 3
#define AMDNVIDIA 4
#define AMDCABLE 0x01
#define AMDBUG 0x02
#define NVIDIA 0x04
#define VIACLK 0x08
#define VIABUG 0x10
#define VIA33 0
#define VIA66 1
#define VIA100 2
#define VIA133 3
#define AMDNVIDIA 4
#define AMDCABLE 0x01
#define AMDBUG 0x02
#define NVIDIA 0x04
#define VIACLK 0x08
#define VIABUG 0x10
/* global prototypes */
int ata_legacy(device_t);
void ata_dmainit(struct ata_channel *);
int ata_dmastart(struct ata_channel *, caddr_t, int32_t, int);
int ata_dmastop(struct ata_channel *);
/* global prototypes ata-pci.c */
int ata_pci_probe(device_t dev);
int ata_pci_attach(device_t dev);
int ata_pci_detach(device_t dev);
struct resource * ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r);
int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *function, void *argument, void **cookiep);
int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie);
extern driver_t ata_channel_driver;
/* global prototypes ata-chipset.c */
int ata_generic_ident(device_t);
int ata_acard_ident(device_t);
int ata_ali_ident(device_t);
@ -346,3 +361,8 @@ int ata_serverworks_ident(device_t);
int ata_sii_ident(device_t);
int ata_sis_ident(device_t);
int ata_via_ident(device_t);
int ata_legacy(device_t);
struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *);
/* global prototypes ata-dma.c */
void ata_dmainit(struct ata_channel *);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,16 +43,18 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/ata/ata-all.h>
#include <ata_if.h>
/* prototypes */
static void ata_completed(void *, int);
static void ata_timeout(struct ata_request *);
static void ata_sort_queue(struct ata_channel *ch, struct ata_request *request);
static char *ata_skey2str(u_int8_t);
void
ata_queue_request(struct ata_request *request)
{
struct ata_channel *ch = request->device->channel;
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
/* mark request as virgin */
request->result = request->status = request->error = 0;
@ -61,16 +63,13 @@ ata_queue_request(struct ata_request *request)
if (!request->callback && !(request->flags & ATA_R_REQUEUE))
sema_init(&request->done, 0, "ATA request done");
/* in IMMEDIATE_MODE we dont queue but call HW directly */
/* used only during reinit for getparm and config */
if ((ch->flags & ATA_IMMEDIATE_MODE) &&
(request->flags & (ATA_R_CONTROL | ATA_R_IMMEDIATE))) {
/* in ATA_STALL_QUEUE state we call HW directly (used only during reinit) */
if ((ch->state & ATA_STALL_QUEUE) && (request->flags & ATA_R_CONTROL)) {
/* arm timeout */
if (!dumping)
callout_reset(&request->callout, request->timeout * hz,
(timeout_t*)ata_timeout, request);
/* kick HW into action */
ch->running = request;
if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) {
@ -84,13 +83,15 @@ ata_queue_request(struct ata_request *request)
else {
/* put request on the locked queue at the specified location */
mtx_lock(&ch->queue_mtx);
if (request->flags & ATA_R_IMMEDIATE)
if (request->flags & ATA_R_AT_HEAD)
TAILQ_INSERT_HEAD(&ch->ata_queue, request, chain);
else if (request->flags & ATA_R_ORDERED)
ata_sort_queue(ch, request);
else
TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain);
mtx_unlock(&ch->queue_mtx);
ATA_DEBUG_RQ(request, "queued");
ata_start(ch);
ata_start(ch->dev);
}
/* if this is a requeued request callback/sleep has been setup */
@ -100,7 +101,12 @@ ata_queue_request(struct ata_request *request)
/* if this is not a callback wait until request is completed */
if (!request->callback) {
ATA_DEBUG_RQ(request, "wait for completition");
sema_wait(&request->done);
while (sema_timedwait(&request->done, request->timeout * hz * 4)) {
device_printf(request->dev,
"req=%p %s semaphore timeout !! DANGER Will Robinson !!\n",
request, ata_cmd2str(request));
ata_start(ch->dev);
}
sema_destroy(&request->done);
}
}
@ -113,13 +119,13 @@ ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature,
int error = ENOMEM;
if (request) {
request->device = atadev;
request->dev = atadev->dev;
request->u.ata.command = command;
request->u.ata.lba = lba;
request->u.ata.count = count;
request->u.ata.feature = feature;
request->flags = ATA_R_CONTROL;
request->timeout = 5;
request->timeout = 1;
request->retries = 0;
ata_queue_request(request);
error = request->result;
@ -136,8 +142,8 @@ ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data,
int error = ENOMEM;
if (request) {
request->device = atadev;
if ((atadev->param->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
request->dev = atadev->dev;
if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
bcopy(ccb, request->u.atapi.ccb, 12);
else
bcopy(ccb, request->u.atapi.ccb, 16);
@ -154,47 +160,58 @@ ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data,
}
void
ata_start(struct ata_channel *ch)
ata_start(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
struct ata_request *request;
/* if in immediate mode, just skip start requests (stall queue) */
if (ch->flags & ATA_IMMEDIATE_MODE)
return;
/* if we dont have any work, ask the subdriver(s) */
mtx_lock(&ch->queue_mtx);
if (TAILQ_EMPTY(&ch->ata_queue)) {
mtx_unlock(&ch->queue_mtx);
if (ch->device[MASTER].start)
ch->device[MASTER].start(&ch->device[MASTER]);
if (ch->device[SLAVE].start)
ch->device[SLAVE].start(&ch->device[SLAVE]);
mtx_lock(&ch->queue_mtx);
}
struct ata_composite *cptr;
int dependencies = 0;
/* if we have a request on the queue try to get it running */
mtx_lock(&ch->queue_mtx);
if ((request = TAILQ_FIRST(&ch->ata_queue))) {
/* we need the locking function to get the lock for this channel */
if (ch->locking(ch, ATA_LF_LOCK) == ch->unit) {
if (ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_LOCK) == ch->unit) {
/* check for the right state */
/* check for composite dependencies */
if ((cptr = request->composite)) {
mtx_lock(&cptr->lock);
if ((request->flags & ATA_R_WRITE) &&
(cptr->wr_depend & cptr->rd_done) != cptr->wr_depend) {
dependencies = 1;
}
mtx_unlock(&cptr->lock);
}
/* check we are int the right state and has no dependencies */
mtx_lock(&ch->state_mtx);
if (ch->state == ATA_IDLE) {
if (ch->state == ATA_IDLE && !dependencies) {
ATA_DEBUG_RQ(request, "starting");
#if 0
if (request->sequence_count)
request = request->sequence[--request->sequence_count];
else
#else
TAILQ_REMOVE(&ch->ata_queue, request, chain);
#endif
ch->running = request;
ch->state = ATA_ACTIVE;
/* if we are the freezing point release it */
if (ch->freezepoint == request)
ch->freezepoint = NULL;
/* arm timeout for this request */
if (!dumping)
callout_reset(&request->callout, request->timeout * hz,
(timeout_t*)ata_timeout, request);
if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) {
ch->running = NULL;
ch->state = ATA_IDLE;
mtx_unlock(&ch->queue_mtx);
mtx_unlock(&ch->state_mtx);
ch->locking(ch, ATA_LF_UNLOCK);
mtx_unlock(&ch->queue_mtx);
ATA_LOCKING(device_get_parent(dev), dev, ATA_LF_UNLOCK);
ata_finish(request);
return;
}
@ -208,25 +225,26 @@ ata_start(struct ata_channel *ch)
void
ata_finish(struct ata_request *request)
{
struct ata_channel *ch = request->device->channel;
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
/* schedule it for completition */
if (ch->flags & ATA_IMMEDIATE_MODE) {
/* if in STALL_QUEUE state or request is ATA_R_DIRECT call complete now */
if ((ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) {
ATA_DEBUG_RQ(request, "finish directly");
ata_completed(request, 0);
}
else {
if (!dumping)
/* reset timeout and put on the proper taskqueue for completition */
if (!dumping && !(request->flags & ATA_R_TIMEOUT))
callout_reset(&request->callout, request->timeout * hz,
(timeout_t*)ata_timeout, request);
if (request->bio && !(request->flags & ATA_R_TIMEOUT)) {
if (request->bio && !(request->flags & (ATA_R_THREAD | ATA_R_TIMEOUT))){
ATA_DEBUG_RQ(request, "finish bio_taskqueue");
bio_taskqueue(request->bio, (bio_task_t *)ata_completed, request);
}
else {
TASK_INIT(&request->task, 0, ata_completed, request);
ATA_DEBUG_RQ(request, "finish taskqueue_thread");
taskqueue_enqueue(taskqueue_thread, &request->task);
ATA_DEBUG_RQ(request, "finish taskqueue_swi");
taskqueue_enqueue(taskqueue_swi, &request->task);
}
}
}
@ -235,7 +253,9 @@ static void
ata_completed(void *context, int dummy)
{
struct ata_request *request = (struct ata_request *)context;
struct ata_channel *ch = request->device->channel;
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
struct ata_device *atadev = device_get_softc(request->dev);
struct ata_composite *composite;
ATA_DEBUG_RQ(request, "completed entered");
@ -245,21 +265,25 @@ ata_completed(void *context, int dummy)
* if reinit succeeds, retries still permit and device didn't
* get removed by the reinit, reinject request
*/
if (!ata_reinit(ch) && request->retries-- > 0
&& request->device->param){
if (!ata_reinit(ch->dev) && request->dev && (request->retries-- > 0)) {
request->flags &= ~(ATA_R_TIMEOUT | ATA_R_DEBUG);
request->flags |= (ATA_R_IMMEDIATE | ATA_R_REQUEUE);
request->donecount = 0;
request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE);
ATA_DEBUG_RQ(request, "completed reinject");
ata_queue_request(request);
return;
}
/* nothing more to try so finish with error */
if (!(request->flags & ATA_R_QUIET))
ata_prtdev(request->device,
"FAILURE - %s timed out\n",
ata_cmd2str(request));
if (!(request->flags & ATA_R_QUIET)) {
if (request->dev) {
device_printf(request->dev,
"FAILURE - %s timed out",
ata_cmd2str(request));
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
}
}
if (!request->result)
request->result = EIO;
}
@ -269,9 +293,9 @@ ata_completed(void *context, int dummy)
/* if this is a soft ECC error warn about it */
if ((request->status & (ATA_S_CORR | ATA_S_ERROR)) == ATA_S_CORR) {
ata_prtdev(request->device,
"WARNING - %s soft error (ECC corrected)",
ata_cmd2str(request));
device_printf(request->dev,
"WARNING - %s soft error (ECC corrected)",
ata_cmd2str(request));
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
@ -280,13 +304,13 @@ ata_completed(void *context, int dummy)
/* if this is a UDMA CRC error, retry request */
if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) {
if (request->retries-- > 0) {
ata_prtdev(request->device,
"WARNING - %s UDMA ICRC error (retrying request)",
ata_cmd2str(request));
device_printf(request->dev,
"WARNING - %s UDMA ICRC error (retrying request)",
ata_cmd2str(request));
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
request->flags |= (ATA_R_IMMEDIATE | ATA_R_REQUEUE);
request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE);
ata_queue_request(request);
return;
}
@ -299,14 +323,15 @@ ata_completed(void *context, int dummy)
default:
if (!request->result && request->status & ATA_S_ERROR) {
if (!(request->flags & ATA_R_QUIET)) {
ata_prtdev(request->device,
"FAILURE - %s status=%b error=%b",
ata_cmd2str(request),
request->status, "\20\10BUSY\7READY\6DMA_READY"
"\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR",
request->error, "\20\10ICRC\7UNCORRECTABLE"
"\6MEDIA_CHANGED\5NID_NOT_FOUND\4MEDIA_CHANGE_REQEST"
"\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH");
device_printf(request->dev,
"FAILURE - %s status=%b error=%b",
ata_cmd2str(request),
request->status, "\20\10BUSY\7READY\6DMA_READY"
"\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR",
request->error, "\20\10ICRC\7UNCORRECTABLE"
"\6MEDIA_CHANGED\5NID_NOT_FOUND"
"\4MEDIA_CHANGE_REQEST"
"\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH");
if ((request->flags & ATA_R_DMA) &&
(request->dmastat & ATA_BMSTAT_ERROR))
printf(" dma=0x%02x", request->dmastat);
@ -314,8 +339,6 @@ ata_completed(void *context, int dummy)
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
}
/* SOS this could be more precise ? XXX */
request->result = EIO;
}
break;
@ -330,7 +353,7 @@ ata_completed(void *context, int dummy)
if (request->error & ATA_SK_MASK &&
request->u.atapi.ccb[0] != ATAPI_REQUEST_SENSE) {
static u_int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0,
sizeof(struct atapi_sense),
sizeof(struct atapi_sense),
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
request->u.atapi.sense_key = request->error;
@ -341,7 +364,7 @@ ata_completed(void *context, int dummy)
request->transfersize = sizeof(struct atapi_sense);
request->timeout = 5;
request->flags &= (ATA_R_ATAPI | ATA_R_QUIET);
request->flags |= (ATA_R_READ | ATA_R_IMMEDIATE | ATA_R_REQUEUE);
request->flags |= (ATA_R_READ | ATA_R_AT_HEAD | ATA_R_REQUEUE);
ATA_DEBUG_RQ(request, "autoissue request sense");
ata_queue_request(request);
return;
@ -349,8 +372,8 @@ ata_completed(void *context, int dummy)
switch (request->u.atapi.sense_key & ATA_SK_MASK) {
case ATA_SK_RECOVERED_ERROR:
ata_prtdev(request->device, "WARNING - %s recovered error\n",
ata_cmd2str(request));
device_printf(request->dev, "WARNING - %s recovered error\n",
ata_cmd2str(request));
/* FALLTHROUGH */
case ATA_SK_NO_SENSE:
@ -362,7 +385,7 @@ ata_completed(void *context, int dummy)
break;
case ATA_SK_UNIT_ATTENTION:
request->device->flags |= ATA_D_MEDIA_CHANGED;
atadev->flags |= ATA_D_MEDIA_CHANGED;
request->result = EIO;
break;
@ -371,12 +394,12 @@ ata_completed(void *context, int dummy)
if (request->flags & ATA_R_QUIET)
break;
ata_prtdev(request->device,
"FAILURE - %s %s asc=0x%02x ascq=0x%02x ",
ata_cmd2str(request), ata_skey2str(
(request->u.atapi.sense_key & ATA_SK_MASK) >> 4),
request->u.atapi.sense_data.asc,
request->u.atapi.sense_data.ascq);
device_printf(request->dev,
"FAILURE - %s %s asc=0x%02x ascq=0x%02x ",
ata_cmd2str(request), ata_skey2str(
(request->u.atapi.sense_key & ATA_SK_MASK) >> 4),
request->u.atapi.sense_data.asc,
request->u.atapi.sense_data.ascq);
if (request->u.atapi.sense_data.sksv)
printf("sks=0x%02x 0x%02x 0x%02x ",
request->u.atapi.sense_data.sk_specific,
@ -395,29 +418,50 @@ ata_completed(void *context, int dummy)
ATA_DEBUG_RQ(request, "completed callback/wakeup");
/* if we are part of a composite operation update progress */
if ((composite = request->composite)) {
int index = 0;
mtx_lock(&composite->lock);
if (request->flags & ATA_R_READ)
composite->rd_done |= (1 << request->this);
if (request->flags & ATA_R_WRITE)
composite->wr_done |= (1 << request->this);
if (composite->wr_depend &&
(composite->rd_done & composite->wr_depend)==composite->wr_depend &&
(composite->wr_needed & (~composite->wr_done))) {
index = ((composite->wr_needed & (~composite->wr_done))) - 1;
}
mtx_unlock(&composite->lock);
if (index)
ata_start(device_get_parent(composite->request[index]->dev));
}
/* get results back to the initiator */
if (request->callback)
(request->callback)(request);
else
sema_post(&request->done);
ata_start(ch);
ata_start(ch->dev);
}
static void
ata_timeout(struct ata_request *request)
{
struct ata_channel *ch = request->device->channel;
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
mtx_lock(&ch->state_mtx);
//request->flags |= ATA_R_DEBUG;
ATA_DEBUG_RQ(request, "timeout");
/* if interrupt has been seen, shout and just rearm timeout */
if (request->flags & ATA_R_INTR_SEEN) {
ata_prtdev(request->device,
"WARNING - %s interrupt was seen but timeout fired",
ata_cmd2str(request));
device_printf(request->dev,
"WARNING - %s interrupt was seen but timeout fired",
ata_cmd2str(request));
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
@ -431,29 +475,29 @@ ata_timeout(struct ata_request *request)
}
/*
* if we are waiting for a command to complete set ATA_TIMEOUT so
* we wont loose the race with an eventual interrupt arriving late
* grap and hold the state lock so we wont loose the race with
* an eventual interrupt arriving late
*/
if (ch->state == ATA_ACTIVE) {
if (ch->state == ATA_ACTIVE || ch->state == ATA_STALL_QUEUE) {
request->flags |= ATA_R_TIMEOUT;
ch->state = ATA_TIMEOUT;
ch->running = NULL;
if (!(request->flags & ATA_R_QUIET) && request->retries > 0) {
ata_prtdev(request->device,
"TIMEOUT - %s retrying (%d retr%s left)",
ata_cmd2str(request), request->retries,
request->retries == 1 ? "y" : "ies");
device_printf(request->dev,
"TIMEOUT - %s retrying (%d retr%s left)",
ata_cmd2str(request), request->retries,
request->retries == 1 ? "y" : "ies");
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
}
ch->hw.end_transaction(request);
ch->state |= ATA_TIMEOUT;
mtx_unlock(&ch->state_mtx);
ATA_LOCKING(device_get_parent(ch->dev), ch->dev, ATA_LF_UNLOCK);
ata_finish(request);
}
else {
mtx_unlock(&ch->state_mtx);
ata_prtdev(request->device, "timeout state=%d unexpected\n", ch->state);
device_printf(request->dev, "timeout state=%d unexpected\n", ch->state);
}
}
@ -468,33 +512,32 @@ ata_catch_inflight(struct ata_channel *ch)
mtx_unlock(&ch->state_mtx);
if (request) {
callout_drain(&request->callout);
ata_prtdev(request->device,
"WARNING - %s requeued due to channel reset",
ata_cmd2str(request));
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
request->flags |= ATA_R_REQUEUE;
ata_queue_request(request);
callout_drain(&request->callout);
device_printf(request->dev,
"WARNING - %s requeued due to channel reset",
ata_cmd2str(request));
if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
request->flags |= ATA_R_REQUEUE;
ata_queue_request(request);
}
}
void
ata_fail_requests(struct ata_channel *ch, struct ata_device *device)
ata_fail_requests(struct ata_channel *ch, device_t dev)
{
struct ata_request *request;
/* fail all requests queued on this channel */
/* fail all requests queued on this channel for device dev if !NULL */
mtx_lock(&ch->queue_mtx);
while ((request = TAILQ_FIRST(&ch->ata_queue))) {
if (!device || request->device == device) {
if (!dev || request->dev == dev) {
TAILQ_REMOVE(&ch->ata_queue, request, chain);
mtx_unlock(&ch->queue_mtx);
request->result = ENXIO;
if (request->callback)
(request->callback)(request);
else
sema_post(&request->done);
ata_finish(request);
mtx_lock(&ch->queue_mtx);
}
}
mtx_unlock(&ch->queue_mtx);
@ -505,16 +548,88 @@ ata_fail_requests(struct ata_channel *ch, struct ata_device *device)
mtx_unlock(&ch->state_mtx);
/* if we have a request "in flight" fail it as well */
if (request && (!device || request->device == device)) {
if (request && (!dev || request->dev == dev)) {
callout_drain(&request->callout);
request->result = ENXIO;
if (request->callback)
(request->callback)(request);
else
sema_post(&request->done);
ata_finish(request);
}
}
static u_int64_t
ata_get_lba(struct ata_request *request)
{
if (request->flags & ATA_R_ATAPI) {
switch (request->u.atapi.ccb[0]) {
case ATAPI_READ_BIG:
case ATAPI_WRITE_BIG:
case ATAPI_READ_CD:
return (request->u.atapi.ccb[5]) | (request->u.atapi.ccb[4]<<8) |
(request->u.atapi.ccb[3]<<16)|(request->u.atapi.ccb[2]<<24);
case ATAPI_READ:
case ATAPI_WRITE:
return (request->u.atapi.ccb[4]) | (request->u.atapi.ccb[3]<<8) |
(request->u.atapi.ccb[2]<<16);
default:
return 0;
}
}
else
return request->u.ata.lba;
}
static void
ata_sort_queue(struct ata_channel *ch, struct ata_request *request)
{
struct ata_request *this, *next;
this = TAILQ_FIRST(&ch->ata_queue);
/* if the queue is empty just insert */
if (!this) {
if (request->composite)
ch->freezepoint = request;
TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain);
return;
}
/* dont sort frozen parts of the queue */
if (ch->freezepoint)
this = ch->freezepoint;
/* if position is less than head we add after tipping point */
if (ata_get_lba(request) < ata_get_lba(this)) {
while ((next = TAILQ_NEXT(this, chain))) {
/* have we reached the tipping point */
if (ata_get_lba(next) < ata_get_lba(this)) {
/* sort the insert */
do {
if (ata_get_lba(request) < ata_get_lba(next))
break;
this = next;
} while ((next = TAILQ_NEXT(this, chain)));
break;
}
this = next;
}
}
/* we are after head so sort the insert before tipping point */
else {
while ((next = TAILQ_NEXT(this, chain))) {
if (ata_get_lba(next) < ata_get_lba(this) ||
ata_get_lba(request) < ata_get_lba(next))
break;
this = next;
}
}
if (request->composite)
ch->freezepoint = request;
TAILQ_INSERT_AFTER(&ch->ata_queue, this, request, chain);
}
char *
ata_cmd2str(struct ata_request *request)
{
@ -579,7 +694,7 @@ ata_cmd2str(struct ata_request *request)
else {
switch (request->u.ata.command) {
case 0x00: return ("NOP");
case 0x08: return ("ATAPI_RESET");
case 0x08: return ("DEVICE_RESET");
case 0x20: return ("READ");
case 0x24: return ("READ48");
case 0x25: return ("READ_DMA48");
@ -590,6 +705,7 @@ ata_cmd2str(struct ata_request *request)
case 0x35: return ("WRITE_DMA48");
case 0x36: return ("WRITE_DMA_QUEUED48");
case 0x39: return ("WRITE_MUL48");
case 0x70: return ("SEEK");
case 0xa0: return ("PACKET_CMD");
case 0xa1: return ("ATAPI_IDENTIFY");
case 0xa2: return ("SERVICE");
@ -612,7 +728,7 @@ ata_cmd2str(struct ata_request *request)
case 0xaa: return ("SETFEATURES ENABLE RCACHE");
case 0x55: return ("SETFEATURES DISABLE RCACHE");
}
sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature);
sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature);
return buffer;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000 - 2003 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 2000 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,273 +29,614 @@
*/
/* misc defines */
#define MAX_ARRAYS 16
#define MAX_DISKS 16
#define AR_PROXIMITY 2048
#define AR_READ 0x01
#define AR_WRITE 0x02
#define AR_WAIT 0x04
#define AR_STRATEGY(x) (x)->bio_disk->d_strategy((x))
#define AD_SOFTC(x) ((struct ad_softc *)(x.device->softc))
#define ATA_MAGIC "FreeBSD ATA driver RAID "
#define MAX_ARRAYS 16
#define MAX_DISKS 16
#define AR_PROXIMITY 2048 /* how many sectors is "close" */
struct ar_disk {
struct ata_device *device;
u_int64_t disk_sectors; /* sectors on this disk */
off_t last_lba; /* last lba used */
int flags;
#define AR_DF_PRESENT 0x00000001
#define AR_DF_ASSIGNED 0x00000002
#define AR_DF_SPARE 0x00000004
#define AR_DF_ONLINE 0x00000008
#define ATA_MAGIC "FreeBSD ATA driver RAID "
struct ata_raid_subdisk {
struct ar_softc *raid;
int disk_number;
};
/* ATA PseudoRAID Metadata */
struct ar_softc {
int lun;
int32_t magic_0; /* ident for this array */
int32_t magic_1; /* ident for this array */
int flags;
#define AR_F_SPAN 0x00000001
#define AR_F_RAID0 0x00000002
#define AR_F_RAID1 0x00000004
#define AR_F_RAID3 0x00000008
#define AR_F_RAID5 0x00000010
int lun; /* logical unit number of this RAID */
u_int8_t name[32]; /* name of array if any */
u_int64_t magic_0; /* magic for this array */
u_int64_t magic_1; /* magic for this array */
int type;
#define AR_T_JBOD 0x0001
#define AR_T_SPAN 0x0002
#define AR_T_RAID0 0x0004
#define AR_T_RAID1 0x0008
#define AR_T_RAID01 0x0010
#define AR_T_RAID3 0x0020
#define AR_T_RAID4 0x0040
#define AR_T_RAID5 0x0080
#define AR_F_READY 0x00000100
#define AR_F_DEGRADED 0x00000200
#define AR_F_REBUILDING 0x00000400
#define AR_F_TOGGLE 0x00000800
int status;
#define AR_S_READY 0x0001
#define AR_S_DEGRADED 0x0002
#define AR_S_REBUILDING 0x0004
#define AR_F_FREEBSD_RAID 0x00010000
#define AR_F_PROMISE_RAID 0x00020000
#define AR_F_HIGHPOINT_RAID 0x00040000
#define AR_F_ADAPTEC_RAID 0x00080000
#define AR_F_LSI_RAID 0x00100000
#define AR_F_INTEL_RAID 0x00200000
#define AR_F_QTEC_RAID 0x00400000
int format;
#define AR_F_FREEBSD_RAID 0x0001
#define AR_F_ADAPTEC_RAID 0x0002
#define AR_F_HPTV2_RAID 0x0004
#define AR_F_HPTV3_RAID 0x0008
#define AR_F_INTEL_RAID 0x0010
#define AR_F_ITE_RAID 0x0020
#define AR_F_LSIV2_RAID 0x0040
#define AR_F_LSIV3_RAID 0x0080
#define AR_F_PROMISE_RAID 0x0100
#define AR_F_SII_RAID 0x0200
#define AR_F_FORMAT_MASK 0x03ff
int total_disks; /* number of disks in this array */
int generation; /* generation of this array */
struct ar_disk disks[MAX_DISKS+1]; /* ptr to each disk in array */
int width; /* array width in disks */
u_int16_t heads;
u_int16_t sectors;
u_int32_t cylinders;
u_int64_t total_sectors;
int interleave; /* interleave in blocks */
int reserved; /* sectors that are NOT to be used */
int offset; /* offset from start of disk */
u_int64_t lock_start; /* start of locked area for rebuild */
u_int64_t lock_end; /* end of locked area for rebuild */
struct disk *disk; /* disklabel/slice stuff */
struct proc *pid; /* rebuilder process id */
u_int generation; /* generation of this array */
u_int64_t total_sectors;
u_int64_t offset_sectors; /* offset from start of disk */
u_int16_t heads;
u_int16_t sectors;
u_int32_t cylinders;
u_int width; /* array width in disks */
u_int interleave; /* interleave in blocks */
u_int total_disks; /* number of disks in this array */
struct ar_disk {
device_t dev;
u_int8_t serial[16]; /* serial # of physical disk */
u_int64_t sectors; /* useable sectors on this disk */
off_t last_lba; /* last lba used (for performance) */
u_int flags;
#define AR_DF_PRESENT 0x0001 /* this HW pos has a disk present */
#define AR_DF_ASSIGNED 0x0002 /* this HW pos assigned to an array */
#define AR_DF_SPARE 0x0004 /* this HW pos is a spare */
#define AR_DF_ONLINE 0x0008 /* this HW pos is online and in use */
} disks[MAX_DISKS];
int toggle; /* performance hack for RAID1's */
u_int64_t rebuild_lba; /* rebuild progress indicator */
struct mtx lock; /* metadata lock */
struct disk *disk; /* disklabel/slice stuff */
struct proc *pid; /* rebuilder process id */
};
struct ar_buf {
struct bio bp; /* must be first element! */
struct bio *org;
struct ar_buf *mirror;
int drive;
int flags;
#define AB_F_DONE 0x01
};
/* Adaptec HostRAID Metadata */
#define ADP_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 17)
/* note all entries are big endian */
struct adaptec_raid_conf {
u_int32_t magic_0; /* 0x0000 */
#define ADP_MAGIC_0 0xc4650790
#define HPT_LBA 9
u_int32_t generation;
u_int16_t dummy_0;
u_int16_t total_configs;
u_int16_t dummy_1;
u_int16_t checksum;
u_int32_t dummy_2; /* 0x0010 */
u_int32_t dummy_3;
u_int32_t flags;
u_int32_t timestamp;
u_int32_t dummy_4[4]; /* 0x0020 */
u_int32_t dummy_5[4]; /* 0x0030 */
struct { /* 0x0040 */
u_int16_t total_disks;
u_int16_t generation;
u_int32_t magic_0;
u_int8_t dummy_0;
u_int8_t type;
#define ADP_T_RAID0 0x00
#define ADP_T_RAID1 0x01
u_int8_t dummy_1;
u_int8_t flags;
struct highpoint_raid_conf {
int8_t filler1[32];
u_int32_t magic;
#define HPT_MAGIC_OK 0x5a7816f0
#define HPT_MAGIC_BAD 0x5a7816fd
u_int8_t dummy_2;
u_int8_t dummy_3;
u_int8_t dummy_4;
u_int8_t dummy_5;
u_int32_t magic_0;
u_int32_t magic_1;
u_int32_t order;
#define HPT_O_RAID0 0x01
#define HPT_O_RAID1 0x02
#define HPT_O_OK 0x04
u_int32_t disk_number;
u_int32_t dummy_6;
u_int32_t sectors;
u_int16_t stripe_shift;
u_int16_t dummy_7;
u_int8_t array_width;
u_int8_t stripe_shift;
u_int8_t type;
#define HPT_T_RAID0 0x00
#define HPT_T_RAID1 0x01
#define HPT_T_RAID01_RAID0 0x02
#define HPT_T_SPAN 0x03
#define HPT_T_RAID_3 0x04
#define HPT_T_RAID_5 0x05
#define HPT_T_SINGLEDISK 0x06
#define HPT_T_RAID01_RAID1 0x07
u_int8_t disk_number;
u_int32_t total_sectors;
u_int32_t disk_mode;
u_int32_t boot_mode;
u_int8_t boot_disk;
u_int8_t boot_protect;
u_int8_t error_log_entries;
u_int8_t error_log_index;
struct {
u_int32_t timestamp;
u_int8_t reason;
#define HPT_R_REMOVED 0xfe
#define HPT_R_BROKEN 0xff
u_int8_t disk;
u_int8_t status;
u_int8_t sectors;
u_int32_t lba;
} errorlog[32];
int8_t filler2[16];
u_int32_t rebuild_lba;
u_int8_t dummy_1;
u_int8_t name_1[15];
u_int8_t dummy_2;
u_int8_t name_2[15];
int8_t filler3[8];
u_int32_t dummy_8[4];
u_int8_t name[16];
} configs[127]; /* x 0x40 bytes */
u_int32_t dummy_6[13]; /* 0x2000 */
u_int32_t magic_1;
#define ADP_MAGIC_1 0x9ff85009
u_int32_t dummy_7[3];
u_int32_t magic_2;
u_int32_t dummy_8[46];
u_int32_t magic_3;
#define ADP_MAGIC_3 0x4d545044
u_int32_t magic_4;
#define ADP_MAGIC_4 0x9ff85009
u_int32_t dummy_9[62];
} __packed;
#define LSI_LBA(adp) (adp->total_secs - 1)
/* Highpoint V2 RocketRAID Metadata */
#define HPTV2_LBA(dev) 9
struct lsi_raid_conf {
u_int8_t lsi_id[6];
#define LSI_MAGIC "$XIDE$"
struct hptv2_raid_conf {
int8_t filler1[32];
u_int32_t magic;
#define HPTV2_MAGIC_OK 0x5a7816f0
#define HPTV2_MAGIC_BAD 0x5a7816fd
u_int8_t dummy_1;
u_int8_t flags;
u_int8_t version[2];
u_int8_t config_entries;
u_int8_t raid_count;
u_int8_t total_disks;
u_int8_t dummy_d;
u_int8_t dummy_e;
u_int8_t dummy_f;
u_int32_t magic_0;
u_int32_t magic_1;
u_int32_t order;
#define HPTV2_O_RAID0 0x01
#define HPTV2_O_RAID1 0x02
#define HPTV2_O_OK 0x04
u_int8_t array_width;
u_int8_t stripe_shift;
u_int8_t type;
#define HPTV2_T_RAID0 0x00
#define HPTV2_T_RAID1 0x01
#define HPTV2_T_RAID01_RAID0 0x02
#define HPTV2_T_SPAN 0x03
#define HPTV2_T_RAID_3 0x04
#define HPTV2_T_RAID_5 0x05
#define HPTV2_T_JBOD 0x06
#define HPTV2_T_RAID01_RAID1 0x07
u_int8_t disk_number;
u_int32_t total_sectors;
u_int32_t disk_mode;
u_int32_t boot_mode;
u_int8_t boot_disk;
u_int8_t boot_protect;
u_int8_t error_log_entries;
u_int8_t error_log_index;
struct {
u_int32_t timestamp;
u_int8_t reason;
#define HPTV2_R_REMOVED 0xfe
#define HPTV2_R_BROKEN 0xff
u_int8_t disk;
u_int8_t status;
u_int8_t sectors;
u_int32_t lba;
} errorlog[32];
int8_t filler2[16];
u_int32_t rebuild_lba;
u_int8_t dummy_1;
u_int8_t name_1[15];
u_int8_t dummy_2;
u_int8_t name_2[15];
int8_t filler3[8];
} __packed;
/* Highpoint V3 RocketRAID Metadata */
#define HPTV3_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 11)
struct hptv3_raid_conf {
u_int32_t magic;
#define HPTV3_MAGIC 0x5a7816f3
u_int32_t magic_0;
u_int8_t checksum_0;
u_int8_t mode;
#define HPTV3_BOOT_MARK 0x01
#define HPTV3_USER_MODE 0x02
u_int8_t user_mode;
u_int8_t config_entries;
struct {
u_int32_t total_sectors;
u_int8_t type;
#define HPTV3_T_SPARE 0x00
#define HPTV3_T_JBOD 0x03
#define HPTV3_T_SPAN 0x04
#define HPTV3_T_RAID0 0x05
#define HPTV3_T_RAID1 0x06
#define HPTV3_T_RAID3 0x07
#define HPTV3_T_RAID5 0x08
u_int8_t total_disks;
u_int8_t disk_number;
u_int8_t stripe_shift;
u_int16_t status;
#define HPTV3_T_NEED_REBUILD 0x01
#define HPTV3_T_RAID5_FLAG 0x02
u_int16_t critical_disks;
u_int32_t rebuild_lba;
} __packed configs[2];
u_int8_t name[16];
u_int32_t timestamp;
u_int8_t description[64];
u_int8_t creator[16];
u_int8_t checksum_1;
u_int8_t dummy_0;
u_int8_t dummy_1;
u_int8_t flags;
#define HPTV3_T_ENABLE_TCQ 0x01
#define HPTV3_T_ENABLE_NCQ 0x02
#define HPTV3_T_ENABLE_WCACHE 0x04
#define HPTV3_T_ENABLE_RCACHE 0x08
struct {
u_int32_t total_sectors;
u_int32_t rebuild_lba;
} __packed configs_high[2];
u_int32_t filler[87];
} __packed;
/* Intel MatrixRAID Metadata */
#define INTEL_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 2)
struct intel_raid_conf {
u_int8_t intel_id[24];
#define INTEL_MAGIC "Intel Raid ISM Cfg Sig. "
u_int8_t version[6];
u_int8_t dummy_0[2];
u_int32_t checksum;
u_int32_t config_size;
u_int32_t config_id;
u_int32_t generation;
u_int32_t dummy_1[2];
u_int8_t total_disks;
u_int8_t total_volumes;
u_int8_t dummy_2[2];
u_int32_t filler_0[39];
struct {
u_int8_t serial[16];
u_int32_t sectors;
u_int32_t id;
u_int32_t flags;
#define INTEL_F_SPARE 0x01
#define INTEL_F_ASSIGNED 0x02
#define INTEL_F_DOWN 0x04
#define INTEL_F_ONLINE 0x08
u_int32_t filler[5];
} __packed disk[1];
u_int32_t filler_1[62];
} __packed;
struct intel_raid_mapping {
u_int8_t name[16];
u_int64_t total_sectors __packed;
u_int32_t state;
u_int32_t reserved;
u_int32_t filler_1[20];
u_int32_t offset;
u_int32_t disk_sectors;
u_int32_t stripe_count;
u_int16_t stripe_sectors;
u_int8_t status;
#define INTEL_S_READY 0x00
#define INTEL_S_DISABLED 0x01
#define INTEL_S_DEGRADED 0x02
#define INTEL_S_FAILURE 0x03
u_int8_t type;
#define INTEL_T_RAID0 0x00
#define INTEL_T_RAID1 0x01
u_int8_t total_disks;
u_int8_t dummy_2[3];
u_int32_t filler_2[7];
u_int32_t disk_idx[1];
} __packed;
/* Integrated Technology Express Metadata */
#define ITE_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 2)
struct ite_raid_conf {
u_int32_t filler_1[5];
u_int8_t timestamp_0[8]; /* BCD coded y:Y:M:D:m:h:f:s */
u_int32_t dummy_1;
u_int32_t filler_2[5];
u_int16_t filler_3;
u_int8_t ite_id[40]; /* byte swapped */
#define ITE_MAGIC "Integrated Technology Express Inc "
u_int16_t filler_4;
u_int32_t filler_5[6];
u_int32_t dummy_2;
u_int32_t dummy_3;
u_int32_t filler_6[12];
u_int32_t dummy_4;
u_int32_t filler_7[5];
u_int64_t total_sectors __packed;
u_int32_t filler_8[12];
u_int16_t filler_9; /* 0x100 */
u_int8_t type;
#define ITE_T_RAID0 0x00
#define ITE_T_RAID1 0x01
#define ITE_T_RAID01 0x02
#define ITE_T_SPAN 0x03
u_int8_t filler_10;
u_int32_t dummy_5[8];
u_int8_t stripe_1kblocks;
u_int8_t filler_11[3];
u_int32_t filler_12[54];
u_int32_t dummy_6[4]; /* 0x200 */
u_int8_t timestamp_1[8]; /* same as timestamp_0 */
u_int32_t filler_13[9];
u_int8_t stripe_sectors;
u_int8_t filler_14[3];
u_int8_t array_width;
u_int8_t filler_15[3];
u_int32_t filler_16;
u_int8_t filler_17;
u_int8_t disk_number;
u_int32_t disk_sectors;
u_int16_t filler_18;
u_int32_t dummy_7[4];
u_int32_t filler_20[104];
} __packed;
/* LSILogic V2 MegaRAID Metadata */
#define LSIV2_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 1)
struct lsiv2_raid_conf {
u_int8_t lsi_id[6];
#define LSIV2_MAGIC "$XIDE$"
u_int8_t dummy_0;
u_int8_t flags;
u_int16_t version;
u_int8_t config_entries;
u_int8_t raid_count;
u_int8_t total_disks;
u_int8_t dummy_1;
u_int16_t dummy_2;
union {
struct {
u_int8_t type;
#define LSI_R_RAID0 0x01
#define LSI_R_RAID1 0x02
#define LSI_R_SPARE 0x08
u_int8_t type;
#define LSIV2_T_RAID0 0x01
#define LSIV2_T_RAID1 0x02
#define LSIV2_T_SPARE 0x08
u_int8_t dummy_1;
u_int16_t stripe_size;
u_int8_t raid_width;
u_int8_t disk_count;
u_int8_t config_offset;
u_int8_t dummy_7;
u_int8_t flags;
#define LSI_R_DEGRADED 0x02
u_int8_t dummy_0;
u_int16_t stripe_sectors;
u_int8_t array_width;
u_int8_t disk_count;
u_int8_t config_offset;
u_int8_t dummy_1;
u_int8_t flags;
#define LSIV2_R_DEGRADED 0x02
u_int32_t total_sectors;
u_int8_t filler[3];
u_int32_t total_sectors;
u_int8_t filler[3];
} __packed raid;
struct {
u_int8_t device;
#define LSI_D_MASTER 0x00
#define LSI_D_SLAVE 0x01
#define LSI_D_CHANNEL0 0x00
#define LSI_D_CHANNEL1 0x10
#define LSI_D_NONE 0xff
u_int8_t device;
#define LSIV2_D_MASTER 0x00
#define LSIV2_D_SLAVE 0x01
#define LSIV2_D_CHANNEL0 0x00
#define LSIV2_D_CHANNEL1 0x10
#define LSIV2_D_NONE 0xff
u_int8_t dummy_1;
u_int32_t disk_sectors;
u_int8_t disk_number;
u_int8_t raid_number;
u_int8_t flags;
#define LSI_D_GONE 0x02
u_int8_t dummy_0;
u_int32_t disk_sectors;
u_int8_t disk_number;
u_int8_t raid_number;
u_int8_t flags;
#define LSIV2_D_GONE 0x02
u_int8_t filler[7];
u_int8_t filler[7];
} __packed disk;
} configs[30];
u_int8_t disk_number;
u_int8_t raid_number;
u_int32_t timestamp;
u_int8_t filler[10];
u_int8_t disk_number;
u_int8_t raid_number;
u_int32_t timestamp;
u_int8_t filler[10];
} __packed;
#define PR_LBA(adp) \
(((adp->total_secs / (adp->heads * adp->sectors)) * \
adp->heads * adp->sectors) - adp->sectors)
/* LSILogic V3 MegaRAID Metadata */
#define LSIV3_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 4)
struct lsiv3_raid_conf {
u_int32_t magic_0; /* 0xa0203200 */
u_int32_t filler_0[3];
u_int8_t magic_1[4]; /* "SATA" */
u_int32_t filler_1[40];
u_int32_t dummy_0; /* 0x0d000003 */
u_int32_t filler_2[7];
u_int32_t dummy_1; /* 0x0d000003 */
u_int32_t filler_3[70];
u_int8_t magic_2[8]; /* "$_ENQ$31" */
u_int8_t filler_4[7];
u_int8_t checksum_0;
u_int8_t filler_5[512*2];
u_int8_t lsi_id[6];
#define LSIV3_MAGIC "$_IDE$"
u_int16_t dummy_2; /* 0x33de for OK disk */
u_int16_t version; /* 0x0131 for this version */
u_int16_t dummy_3; /* 0x0440 always */
u_int32_t filler_6;
struct {
u_int16_t stripe_pages;
u_int8_t type;
#define LSIV3_T_RAID0 0x00
#define LSIV3_T_RAID1 0x01
u_int8_t dummy_0;
u_int8_t total_disks;
u_int8_t array_width;
u_int8_t filler_0[10];
u_int32_t sectors;
u_int16_t dummy_1;
u_int32_t offset;
u_int16_t dummy_2;
u_int8_t device;
#define LSIV3_D_DEVICE 0x01
#define LSIV3_D_CHANNEL 0x10
u_int8_t dummy_3;
u_int8_t dummy_4;
u_int8_t dummy_5;
u_int8_t filler_1[16];
} __packed raid[8];
struct {
u_int32_t disk_sectors;
u_int32_t dummy_0;
u_int32_t dummy_1;
u_int8_t dummy_2;
u_int8_t dummy_3;
u_int8_t flags;
#define LSIV3_D_MIRROR 0x00
#define LSIV3_D_STRIPE 0xff
u_int8_t dummy_4;
} __packed disk[6];
u_int8_t filler_7[7];
u_int8_t device;
u_int32_t timestamp;
u_int8_t filler_8[3];
u_int8_t checksum_1;
} __packed;
/* Promise FastTrak Metadata */
#define PR_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 63)
#if 0
(((((struct ad_softc *)device_get_ivars(dev))->total_secs / (((struct ad_softc *)device_get_ivars(dev))->heads * ((struct ad_softc *)device_get_ivars(dev))->sectors)) * ((struct ad_softc *)device_get_ivars(dev))->heads * ((struct ad_softc *)device_get_ivars(dev))->sectors) - ((struct ad_softc *)device_get_ivars(dev))->sectors)
#endif
struct promise_raid_conf {
char promise_id[24];
#define PR_MAGIC "Promise Technology, Inc."
char promise_id[24];
#define PR_MAGIC "Promise Technology, Inc."
u_int32_t dummy_0;
u_int64_t magic_0;
#define PR_MAGIC0(x) (x.device ? ((u_int64_t)x.device->channel->unit<<48) | \
((u_int64_t)(x.device->unit != 0) << 56) : 0)
u_int16_t magic_1;
u_int32_t magic_2;
u_int8_t filler1[470];
u_int32_t dummy_0;
u_int64_t magic_0;
#define PR_MAGIC0(x) (((u_int64_t)(x.channel) << 48) | \
((u_int64_t)(x.device != 0) << 56))
u_int16_t magic_1;
u_int32_t magic_2;
u_int8_t filler1[470];
struct {
u_int32_t integrity;
#define PR_I_VALID 0x00000080
u_int32_t integrity;
#define PR_I_VALID 0x00000080
u_int8_t flags;
#define PR_F_VALID 0x00000001
#define PR_F_ONLINE 0x00000002
#define PR_F_ASSIGNED 0x00000004
#define PR_F_SPARE 0x00000008
#define PR_F_DUPLICATE 0x00000010
#define PR_F_REDIR 0x00000020
#define PR_F_DOWN 0x00000040
#define PR_F_READY 0x00000080
u_int8_t flags;
#define PR_F_VALID 0x00000001
#define PR_F_ONLINE 0x00000002
#define PR_F_ASSIGNED 0x00000004
#define PR_F_SPARE 0x00000008
#define PR_F_DUPLICATE 0x00000010
#define PR_F_REDIR 0x00000020
#define PR_F_DOWN 0x00000040
#define PR_F_READY 0x00000080
u_int8_t disk_number;
u_int8_t channel;
u_int8_t device;
u_int64_t magic_0 __packed;
u_int32_t disk_offset;
u_int32_t disk_sectors;
u_int32_t rebuild_lba;
u_int16_t generation;
u_int8_t status;
#define PR_S_VALID 0x01
#define PR_S_ONLINE 0x02
#define PR_S_INITED 0x04
#define PR_S_READY 0x08
#define PR_S_DEGRADED 0x10
#define PR_S_MARKED 0x20
#define PR_S_FUNCTIONAL 0x80
u_int8_t disk_number;
u_int8_t channel;
u_int8_t device;
u_int64_t magic_0 __packed;
u_int32_t disk_offset;
u_int32_t disk_sectors;
u_int32_t rebuild_lba;
u_int16_t generation;
u_int8_t status;
#define PR_S_VALID 0x01
#define PR_S_ONLINE 0x02
#define PR_S_INITED 0x04
#define PR_S_READY 0x08
#define PR_S_DEGRADED 0x10
#define PR_S_MARKED 0x20
#define PR_S_FUNCTIONAL 0x80
u_int8_t type;
#define PR_T_RAID0 0x00
#define PR_T_RAID1 0x01
#define PR_T_RAID3 0x02
#define PR_T_RAID5 0x04
#define PR_T_SPAN 0x08
u_int8_t type;
#define PR_T_RAID0 0x00
#define PR_T_RAID1 0x01
#define PR_T_RAID3 0x02
#define PR_T_RAID5 0x04
#define PR_T_SPAN 0x08
#define PR_T_JBOD 0x10
u_int8_t total_disks;
u_int8_t stripe_shift;
u_int8_t array_width;
u_int8_t array_number;
u_int32_t total_sectors;
u_int16_t cylinders;
u_int8_t heads;
u_int8_t sectors;
int64_t magic_1 __packed;
u_int8_t total_disks;
u_int8_t stripe_shift;
u_int8_t array_width;
u_int8_t array_number;
u_int32_t total_sectors;
u_int16_t cylinders;
u_int8_t heads;
u_int8_t sectors;
u_int64_t magic_1 __packed;
struct {
u_int8_t flags;
u_int8_t dummy_0;
u_int8_t channel;
u_int8_t device;
u_int64_t magic_0 __packed;
u_int8_t flags;
u_int8_t dummy_0;
u_int8_t channel;
u_int8_t device;
u_int64_t magic_0 __packed;
} disk[8];
} raid;
int32_t filler2[346];
u_int32_t checksum;
int32_t filler2[346];
u_int32_t checksum;
} __packed;
int ata_raiddisk_attach(struct ad_softc *);
int ata_raiddisk_detach(struct ad_softc *);
void ata_raid_attach(void);
int ata_raid_create(struct raid_setup *);
int ata_raid_delete(int);
int ata_raid_status(int, struct raid_status *);
int ata_raid_addspare(int, int);
int ata_raid_rebuild(int);
/* Silicon Image Medley Metadata */
#define SII_LBA(dev) \
( ((struct ad_softc *)device_get_ivars(dev))->total_secs - 1)
struct sii_raid_conf {
u_int16_t ata_params_00_53[54];
u_int64_t total_sectors;
u_int16_t ata_params_58_79[70];
u_int16_t dummy_0;
u_int16_t dummy_1;
u_int32_t controller_pci_id;
u_int16_t version_minor;
u_int16_t version_major;
u_int8_t timestamp[6]; /* BCD coded s:m:h:D:M:Y */
u_int16_t stripe_sectors;
u_int16_t dummy_2;
u_int8_t disk_number;
u_int8_t type;
#define SII_T_RAID0 0x00
#define SII_T_RAID1 0x01
#define SII_T_RAID01 0x02
#define SII_T_SPARE 0x03
u_int8_t raid0_disks;
u_int8_t raid0_ident;
u_int8_t raid1_disks;
u_int8_t raid1_ident;
u_int64_t rebuild_lba;
u_int32_t generation;
u_int8_t status;
#define SII_S_READY 0x01
u_int8_t base_raid1_position;
u_int8_t base_raid0_position;
u_int8_t position;
u_int16_t dummy_3;
u_int8_t name[16];
u_int16_t checksum_0;
int8_t filler1[190];
u_int16_t checksum_1; /* sum of all 128 shorts == 0 */
} __packed;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,48 +31,48 @@
/* CDROM Table Of Contents */
#define MAXTRK 99
struct toc {
struct ioc_toc_header hdr;
struct cd_toc_entry tab[MAXTRK + 1];
struct ioc_toc_header hdr;
struct cd_toc_entry tab[MAXTRK + 1];
};
/* DVD CSS authentication */
struct dvd_miscauth {
u_int16_t length;
u_int16_t reserved;
u_int8_t data[2048];
u_int16_t length;
u_int16_t reserved;
u_int8_t data[2048];
};
/* CDROM Audio Control Parameters Page */
struct audiopage {
/* mode page data header */
u_int16_t data_length;
u_int8_t medium_type;
u_int8_t dev_spec;
u_int8_t unused[2];
u_int16_t blk_desc_len;
u_int16_t data_length;
u_int8_t medium_type;
u_int8_t dev_spec;
u_int8_t unused[2];
u_int16_t blk_desc_len;
/* audio control page */
u_int8_t page_code;
#define ATAPI_CDROM_AUDIO_PAGE 0x0e
u_int8_t page_code;
#define ATAPI_CDROM_AUDIO_PAGE 0x0e
#define ATAPI_CDROM_AUDIO_PAGE_MASK 0x4e
u_int8_t param_len;
u_int8_t flags;
#define CD_PA_SOTC 0x02
#define CD_PA_IMMED 0x04
u_int8_t param_len;
u_int8_t flags;
#define CD_PA_SOTC 0x02
#define CD_PA_IMMED 0x04
u_int8_t reserved3;
u_int8_t reserved4;
u_int8_t reserved5;
u_int16_t lb_per_sec;
u_int8_t reserved3;
u_int8_t reserved4;
u_int8_t reserved5;
u_int16_t lb_per_sec;
struct port_control {
u_int8_t channels:4;
#define CHANNEL_0 1
#define CHANNEL_1 2
#define CHANNEL_2 4
#define CHANNEL_3 8
u_int8_t channels:4;
#define CHANNEL_0 1
#define CHANNEL_1 2
#define CHANNEL_2 4
#define CHANNEL_3 8
u_int8_t volume;
u_int8_t volume;
} port[4];
};
@ -80,241 +80,237 @@ struct audiopage {
/* CDROM Capabilities and Mechanical Status Page */
struct cappage {
/* mode page data header */
u_int16_t data_length;
u_int8_t medium_type;
#define MST_TYPE_MASK_LOW 0x0f
#define MST_FMT_NONE 0x00
#define MST_DATA_120 0x01
#define MST_AUDIO_120 0x02
#define MST_COMB_120 0x03
#define MST_PHOTO_120 0x04
#define MST_DATA_80 0x05
#define MST_AUDIO_80 0x06
#define MST_COMB_80 0x07
#define MST_PHOTO_80 0x08
u_int16_t data_length;
u_int8_t medium_type;
#define MST_TYPE_MASK_LOW 0x0f
#define MST_FMT_NONE 0x00
#define MST_DATA_120 0x01
#define MST_AUDIO_120 0x02
#define MST_COMB_120 0x03
#define MST_PHOTO_120 0x04
#define MST_DATA_80 0x05
#define MST_AUDIO_80 0x06
#define MST_COMB_80 0x07
#define MST_PHOTO_80 0x08
#define MST_TYPE_MASK_HIGH 0x70
#define MST_CDROM 0x00
#define MST_CDR 0x10
#define MST_CDRW 0x20
#define MST_TYPE_MASK_HIGH 0x70
#define MST_CDROM 0x00
#define MST_CDR 0x10
#define MST_CDRW 0x20
#define MST_NO_DISC 0x70
#define MST_DOOR_OPEN 0x71
#define MST_FMT_ERROR 0x72
#define MST_NO_DISC 0x70
#define MST_DOOR_OPEN 0x71
#define MST_FMT_ERROR 0x72
u_int8_t dev_spec;
u_int16_t unused;
u_int16_t blk_desc_len;
u_int8_t dev_spec;
u_int16_t unused;
u_int16_t blk_desc_len;
/* capabilities page */
u_int8_t page_code;
#define ATAPI_CDROM_CAP_PAGE 0x2a
u_int8_t page_code;
#define ATAPI_CDROM_CAP_PAGE 0x2a
u_int8_t param_len;
u_int8_t param_len;
u_int16_t media;
#define MST_READ_CDR 0x0001
#define MST_READ_CDRW 0x0002
#define MST_READ_PACKET 0x0004
#define MST_READ_DVDROM 0x0008
#define MST_READ_DVDR 0x0010
#define MST_READ_DVDRAM 0x0020
#define MST_WRITE_CDR 0x0100
#define MST_WRITE_CDRW 0x0200
#define MST_WRITE_TEST 0x0400
#define MST_WRITE_DVDR 0x1000
#define MST_WRITE_DVDRAM 0x2000
u_int16_t media;
#define MST_READ_CDR 0x0001
#define MST_READ_CDRW 0x0002
#define MST_READ_PACKET 0x0004
#define MST_READ_DVDROM 0x0008
#define MST_READ_DVDR 0x0010
#define MST_READ_DVDRAM 0x0020
#define MST_WRITE_CDR 0x0100
#define MST_WRITE_CDRW 0x0200
#define MST_WRITE_TEST 0x0400
#define MST_WRITE_DVDR 0x1000
#define MST_WRITE_DVDRAM 0x2000
u_int16_t capabilities;
#define MST_AUDIO_PLAY 0x0001
#define MST_COMPOSITE 0x0002
#define MST_AUDIO_P1 0x0004
#define MST_AUDIO_P2 0x0008
#define MST_MODE2_f1 0x0010
#define MST_MODE2_f2 0x0020
#define MST_MULTISESSION 0x0040
#define MST_BURNPROOF 0x0080
#define MST_READ_CDDA 0x0100
#define MST_CDDA_STREAM 0x0200
#define MST_COMBINED_RW 0x0400
#define MST_CORRECTED_RW 0x0800
#define MST_SUPPORT_C2 0x1000
#define MST_ISRC 0x2000
#define MST_UPC 0x4000
u_int16_t capabilities;
#define MST_AUDIO_PLAY 0x0001
#define MST_COMPOSITE 0x0002
#define MST_AUDIO_P1 0x0004
#define MST_AUDIO_P2 0x0008
#define MST_MODE2_f1 0x0010
#define MST_MODE2_f2 0x0020
#define MST_MULTISESSION 0x0040
#define MST_BURNPROOF 0x0080
#define MST_READ_CDDA 0x0100
#define MST_CDDA_STREAM 0x0200
#define MST_COMBINED_RW 0x0400
#define MST_CORRECTED_RW 0x0800
#define MST_SUPPORT_C2 0x1000
#define MST_ISRC 0x2000
#define MST_UPC 0x4000
u_int8_t mechanism;
#define MST_LOCKABLE 0x01
#define MST_LOCKED 0x02
#define MST_PREVENT 0x04
#define MST_EJECT 0x08
#define MST_MECH_MASK 0xe0
#define MST_MECH_CADDY 0x00
#define MST_MECH_TRAY 0x20
#define MST_MECH_POPUP 0x40
#define MST_MECH_CHANGER 0x80
#define MST_MECH_CARTRIDGE 0xa0
u_int8_t mechanism;
#define MST_LOCKABLE 0x01
#define MST_LOCKED 0x02
#define MST_PREVENT 0x04
#define MST_EJECT 0x08
#define MST_MECH_MASK 0xe0
#define MST_MECH_CADDY 0x00
#define MST_MECH_TRAY 0x20
#define MST_MECH_POPUP 0x40
#define MST_MECH_CHANGER 0x80
#define MST_MECH_CARTRIDGE 0xa0
uint8_t audio;
#define MST_SEP_VOL 0x01
#define MST_SEP_MUTE 0x02
uint8_t audio;
#define MST_SEP_VOL 0x01
#define MST_SEP_MUTE 0x02
u_int16_t max_read_speed; /* max raw data rate in bytes/1000 */
u_int16_t max_vol_levels; /* number of discrete volume levels */
u_int16_t buf_size; /* internal buffer size in bytes/1024 */
u_int16_t cur_read_speed; /* current data rate in bytes/1000 */
u_int16_t max_read_speed; /* max raw data rate in bytes/1000 */
u_int16_t max_vol_levels; /* number of discrete volume levels */
u_int16_t buf_size; /* internal buffer size in bytes/1024 */
u_int16_t cur_read_speed; /* current data rate in bytes/1000 */
u_int8_t reserved3;
u_int8_t misc;
u_int8_t reserved3;
u_int8_t misc;
u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */
u_int16_t cur_write_speed; /* current data rate in bytes/1000 */
u_int16_t copy_protect_rev;
u_int16_t reserved4;
u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */
u_int16_t cur_write_speed; /* current data rate in bytes/1000 */
u_int16_t copy_protect_rev;
u_int16_t reserved4;
};
#define CH_READY 0
#define CH_LOADING 1
#define CH_UNLOADING 2
#define CH_INITIALIZING 3
#define CH_READY 0
#define CH_LOADING 1
#define CH_UNLOADING 2
#define CH_INITIALIZING 3
#define CD_IDLE 0
#define CD_AUDIO_ACTIVE 1
#define CD_AUDIO_SCAN 2
#define CD_HOST_ACTIVE 3
#define CD_NO_STATE 7
#define CD_IDLE 0
#define CD_AUDIO_ACTIVE 1
#define CD_AUDIO_SCAN 2
#define CD_HOST_ACTIVE 3
#define CD_NO_STATE 7
/* CDROM Changer mechanism status structure */
struct changer {
u_int8_t current_slot :5; /* active changer slot */
u_int8_t mech_state :2; /* current changer state */
u_int8_t current_slot :5; /* active changer slot */
u_int8_t mech_state :2; /* current changer state */
u_int8_t fault :1; /* fault in last operation */
u_int8_t reserved0 :5;
u_int8_t cd_state :3; /* current mechanism state */
u_int8_t fault :1; /* fault in last operation */
u_int8_t reserved0 :5;
u_int8_t cd_state :3; /* current mechanism state */
u_int8_t current_lba[3]; /* current LBA */
u_int8_t slots; /* number of available slots */
u_int16_t table_length; /* slot table length */
u_int8_t current_lba[3]; /* current LBA */
u_int8_t slots; /* number of available slots */
u_int16_t table_length; /* slot table length */
struct {
u_int8_t changed :1; /* media has changed in this slot */
u_int8_t unused :6;
u_int8_t present :1; /* slot has a CD present */
u_int8_t reserved0;
u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t changed :1; /* media has changed in this slot */
u_int8_t unused :6;
u_int8_t present :1; /* slot has a CD present */
u_int8_t reserved0;
u_int8_t reserved1;
u_int8_t reserved2;
} slot[32];
};
/* CDROM Write Parameters Mode Page (Burners ONLY) */
struct write_param {
/* mode page data header */
u_int16_t data_length;
u_int8_t medium_type;
u_int8_t dev_spec;
u_int8_t unused[2];
u_int16_t blk_desc_len;
u_int16_t data_length;
u_int8_t medium_type;
u_int8_t dev_spec;
u_int8_t unused[2];
u_int16_t blk_desc_len;
/* write parameters page */
u_int8_t page_code;
u_int8_t page_code;
#define ATAPI_CDROM_WRITE_PARAMETERS_PAGE 0x05
u_int8_t page_length; /* 0x32 */
u_int8_t write_type :4; /* write stream type */
#define CDR_WTYPE_PACKET 0x00
#define CDR_WTYPE_TRACK 0x01
#define CDR_WTYPE_SESSION 0x02
#define CDR_WTYPE_RAW 0x03
u_int8_t page_length; /* 0x32 */
u_int8_t write_type :4; /* write stream type */
#define CDR_WTYPE_PACKET 0x00
#define CDR_WTYPE_TRACK 0x01
#define CDR_WTYPE_SESSION 0x02
#define CDR_WTYPE_RAW 0x03
u_int8_t test_write :1; /* test write enable */
u_int8_t link_size_valid :1;
u_int8_t burnproof :1; /* BurnProof enable */
u_int8_t reserved2_7 :1;
u_int8_t track_mode :4; /* track mode */
#define CDR_TMODE_AUDIO 0x00
#define CDR_TMODE_AUDIO_PREEMP 0x01
#define CDR_TMODE_ALLOW_COPY 0x02
#define CDR_TMODE_DATA 0x04
#define CDR_TMODE_QUAD_AUDIO 0x08
u_int8_t test_write :1; /* test write enable */
u_int8_t link_size_valid :1;
u_int8_t burnproof :1; /* BurnProof enable */
u_int8_t reserved2_7 :1;
u_int8_t track_mode :4; /* track mode */
#define CDR_TMODE_AUDIO 0x00
#define CDR_TMODE_AUDIO_PREEMP 0x01
#define CDR_TMODE_ALLOW_COPY 0x02
#define CDR_TMODE_DATA 0x04
#define CDR_TMODE_QUAD_AUDIO 0x08
u_int8_t copy :1; /* generation stamp */
u_int8_t fp :1; /* fixed packet type */
u_int8_t session_type :2; /* session type */
#define CDR_SESS_NONE 0x00
#define CDR_SESS_FINAL 0x01
#define CDR_SESS_RESERVED 0x02
#define CDR_SESS_MULTI 0x03
u_int8_t copy :1; /* generation stamp */
u_int8_t fp :1; /* fixed packet type */
u_int8_t session_type :2; /* session type */
#define CDR_SESS_NONE 0x00
#define CDR_SESS_FINAL 0x01
#define CDR_SESS_RESERVED 0x02
#define CDR_SESS_MULTI 0x03
u_int8_t datablock_type :4; /* data type code (see cdrio.h) */
u_int8_t reserved4_4567 :4;
u_int8_t link_size;
u_int8_t reserved6;
u_int8_t host_app_code :6; /* host application code */
u_int8_t reserved7_67 :2;
u_int8_t session_format; /* session format */
#define CDR_SESS_CDROM 0x00
#define CDR_SESS_CDI 0x10
#define CDR_SESS_CDROM_XA 0x20
u_int8_t datablock_type :4; /* data type code (see cdrio.h) */
u_int8_t reserved4_4567 :4;
u_int8_t link_size;
u_int8_t reserved6;
u_int8_t host_app_code :6; /* host application code */
u_int8_t reserved7_67 :2;
u_int8_t session_format; /* session format */
#define CDR_SESS_CDROM 0x00
#define CDR_SESS_CDI 0x10
#define CDR_SESS_CDROM_XA 0x20
u_int8_t reserved9;
u_int32_t packet_size; /* packet size in bytes */
u_int16_t audio_pause_length; /* audio pause length in secs */
u_int8_t media_catalog_number[16];
u_int8_t isr_code[16];
u_int8_t sub_hdr_byte0;
u_int8_t sub_hdr_byte1;
u_int8_t sub_hdr_byte2;
u_int8_t sub_hdr_byte3;
u_int8_t vendor_specific_byte0;
u_int8_t vendor_specific_byte1;
u_int8_t vendor_specific_byte2;
u_int8_t vendor_specific_byte3;
u_int8_t reserved9;
u_int32_t packet_size; /* packet size in bytes */
u_int16_t audio_pause_length; /* audio pause length in secs */
u_int8_t media_catalog_number[16];
u_int8_t isr_code[16];
u_int8_t sub_hdr_byte0;
u_int8_t sub_hdr_byte1;
u_int8_t sub_hdr_byte2;
u_int8_t sub_hdr_byte3;
u_int8_t vendor_specific_byte0;
u_int8_t vendor_specific_byte1;
u_int8_t vendor_specific_byte2;
u_int8_t vendor_specific_byte3;
} __packed;
/* CDROM Read Track Information structure */
struct acd_track_info {
u_int16_t data_length;
u_int8_t track_number; /* current track number */
u_int8_t session_number; /* current session number */
u_int8_t reserved4;
u_int8_t track_mode :4; /* mode of this track */
u_int8_t copy :1; /* generation stamp */
u_int8_t damage :1; /* damaged track */
u_int8_t reserved5_67 :2;
u_int8_t data_mode :4; /* data mode of this disc */
u_int8_t fp :1; /* fixed packet */
u_int8_t packet :1; /* packet track */
u_int8_t blank :1; /* blank (empty) track */
u_int8_t rt :1; /* reserved track */
u_int8_t nwa_valid :1; /* next_writeable_addr field valid */
u_int8_t reserved7_17 :7;
u_int track_start_addr; /* start of this track */
u_int next_writeable_addr; /* next writeable addr on this disc */
u_int free_blocks; /* free block on this disc */
u_int fixed_packet_size; /* size of packets on this track */
u_int track_length; /* length of this track */
u_int16_t data_length;
u_int8_t track_number; /* current track number */
u_int8_t session_number; /* current session number */
u_int8_t reserved4;
u_int8_t track_mode :4; /* mode of this track */
u_int8_t copy :1; /* generation stamp */
u_int8_t damage :1; /* damaged track */
u_int8_t reserved5_67 :2;
u_int8_t data_mode :4; /* data mode of this disc */
u_int8_t fp :1; /* fixed packet */
u_int8_t packet :1; /* packet track */
u_int8_t blank :1; /* blank (empty) track */
u_int8_t rt :1; /* reserved track */
u_int8_t nwa_valid :1; /* next_writeable_addr field valid */
u_int8_t reserved7_17 :7;
u_int track_start_addr; /* start of this track */
u_int next_writeable_addr; /* next writeable addr on this disc */
u_int free_blocks; /* free block on this disc */
u_int fixed_packet_size; /* size of packets on this track */
u_int track_length; /* length of this track */
};
/* Structure describing an ATAPI CDROM device */
struct acd_softc {
struct ata_device *device; /* device softc */
int lun; /* logical device unit */
int flags; /* device state flags */
#define F_LOCKED 0x0001 /* this unit is locked */
int flags; /* device state flags */
#define F_LOCKED 0x0001 /* this unit is locked */
struct mtx queue_mtx; /* bio queue lock */
struct bio_queue_head queue; /* queue of i/o requests */
struct toc toc; /* table of disc contents */
struct audiopage au; /* audio page info */
struct audiopage aumask; /* audio page mask */
struct cappage cap; /* capabilities page info */
struct cd_sub_channel_info subchan; /* subchannel info */
struct changer *changer_info; /* changer info */
struct acd_softc **driver; /* softc's of changer slots */
int slot; /* this instance slot number */
time_t timestamp; /* this instance timestamp */
u_int32_t disk_size; /* size of current media */
u_int32_t block_size; /* blocksize currently used */
u_int32_t iomax; /* Max I/O request (bytes) */
struct g_geom *gp; /* geom instance */
struct g_provider *pp[MAXTRK+1]; /* providers */
struct toc toc; /* table of disc contents */
struct audiopage au; /* audio page info */
struct audiopage aumask; /* audio page mask */
struct cappage cap; /* capabilities page info */
struct cd_sub_channel_info subchan; /* subchannel info */
struct changer *changer_info; /* changer info */
struct acd_softc **driver; /* softc's of changer slots */
int slot; /* this instance slot number */
time_t timestamp; /* this instance timestamp */
u_int32_t disk_size; /* size of current media */
u_int32_t block_size; /* blocksize currently used */
u_int32_t iomax; /* Max I/O request (bytes) */
struct g_geom *gp; /* geom instance */
struct g_provider *pp[MAXTRK+1]; /* providers */
};

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/ata.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/bio.h>
#include <sys/bus.h>
@ -45,120 +46,273 @@ __FBSDID("$FreeBSD$");
#include <geom/geom_disk.h>
#include <dev/ata/ata-all.h>
#include <dev/ata/atapi-fd.h>
#include <ata_if.h>
/* prototypes */
static disk_open_t afd_open;
static disk_close_t afd_close;
#ifdef notyet
static disk_ioctl_t afd_ioctl;
#endif
static disk_strategy_t afdstrategy;
static void afd_detach(struct ata_device *);
static void afd_start(struct ata_device *);
static int afd_sense(struct afd_softc *);
static void afd_describe(struct afd_softc *);
static disk_open_t afd_open;
static disk_close_t afd_close;
static disk_strategy_t afd_strategy;
static int afd_sense(device_t);
static void afd_describe(device_t);
static void afd_done(struct ata_request *);
static int afd_eject(struct afd_softc *, int);
static int afd_start_stop(struct afd_softc *, int);
static int afd_prevent_allow(struct afd_softc *, int);
static int afd_test_ready(struct ata_device *);
static int afd_prevent_allow(device_t, int);
static int afd_test_ready(device_t);
/* internal vars */
static u_int32_t afd_lun_map = 0;
static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
void
afd_attach(struct ata_device *atadev)
static void
afd_identify(driver_t *driver, device_t parent)
{
ata_identify(driver, parent, ATA_ATAPI_TYPE_DIRECT, "afd");
}
static int
afd_probe(device_t dev)
{
return 0;
}
static int
afd_attach(device_t dev)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp;
fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO);
if (!fdp) {
ata_prtdev(atadev, "out of memory\n");
return;
if (!(fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO))) {
device_printf(dev, "out of memory\n");
device_set_softc(dev, NULL);
free(atadev, M_ATA);
return ENOMEM;
}
device_set_ivars(dev, fdp);
ATA_SETMODE(GRANDPARENT(dev), dev);
fdp->device = atadev;
fdp->lun = ata_get_lun(&afd_lun_map);
ata_set_name(atadev, "afd", fdp->lun);
bioq_init(&fdp->queue);
mtx_init(&fdp->queue_mtx, "ATAPI FD bioqueue lock", NULL, MTX_DEF);
if (afd_sense(fdp)) {
if (afd_sense(dev)) {
device_set_ivars(dev, NULL);
free(fdp, M_AFD);
return;
device_set_softc(dev, NULL);
free(atadev, M_ATA);
return ENXIO;
}
/* setup the function ptrs */
atadev->detach = afd_detach;
atadev->start = afd_start;
atadev->softc = fdp;
atadev->flags |= ATA_D_MEDIA_CHANGED;
/* lets create the disk device */
/* announce we are here */
afd_describe(dev);
/* create the disk device */
fdp->disk = disk_alloc();
fdp->disk->d_open = afd_open;
fdp->disk->d_close = afd_close;
#ifdef notyet
fdp->disk->d_ioctl = afd_ioctl;
#endif
fdp->disk->d_strategy = afdstrategy;
fdp->disk->d_strategy = afd_strategy;
fdp->disk->d_name = "afd";
fdp->disk->d_drv1 = fdp;
if (atadev->channel->dma)
fdp->disk->d_maxsize = atadev->channel->dma->max_iosize;
fdp->disk->d_drv1 = dev;
if (ch->dma)
fdp->disk->d_maxsize = ch->dma->max_iosize;
else
fdp->disk->d_maxsize = DFLTPHYS;
fdp->disk->d_unit = fdp->lun;
fdp->disk->d_unit = device_get_unit(dev);
disk_create(fdp->disk, DISK_VERSION);
return 0;
}
/* announce we are here */
afd_describe(fdp);
static int
afd_detach(device_t dev)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp = device_get_ivars(dev);
/* detroy disk from the system so we dont get any further requests */
disk_destroy(fdp->disk);
/* fail requests on the queue and any thats "in flight" for this device */
ata_fail_requests(ch, dev);
/* dont leave anything behind */
device_set_ivars(dev, NULL);
free(fdp, M_AFD);
device_set_softc(dev, NULL);
free(atadev, M_ATA);
return 0;
}
static void
afd_detach(struct ata_device *atadev)
{
struct afd_softc *fdp = atadev->softc;
afd_shutdown(device_t dev)
{
struct ata_device *atadev = device_get_softc(dev);
if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
ata_controlcmd(atadev, ATA_FLUSHCACHE, 0, 0, 0);
}
static int
afd_reinit(device_t dev)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp = device_get_ivars(dev);
mtx_lock(&fdp->queue_mtx);
bioq_flush(&fdp->queue, NULL, ENXIO);
mtx_unlock(&fdp->queue_mtx);
mtx_destroy(&fdp->queue_mtx);
disk_destroy(fdp->disk);
ata_prtdev(atadev, "WARNING - removed from configuration\n");
ata_free_name(atadev);
ata_free_lun(&afd_lun_map, fdp->lun);
atadev->attach = NULL;
atadev->detach = NULL;
atadev->start = NULL;
atadev->softc = NULL;
atadev->flags = 0;
free(fdp, M_AFD);
}
if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATAPI_MASTER)) ||
((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATAPI_SLAVE))) {
device_set_ivars(dev, NULL);
free(fdp, M_AFD);
return 1;
}
ATA_SETMODE(GRANDPARENT(dev), dev);
return 0;
}
static int
afd_open(struct disk *dp)
{
device_t dev = dp->d_drv1;
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp = device_get_ivars(dev);
if (!fdp)
return ENXIO;
if (!device_is_attached(dev))
return EBUSY;
afd_test_ready(dev);
afd_prevent_allow(dev, 1);
if (afd_sense(dev))
device_printf(dev, "sense media type failed\n");
atadev->flags &= ~ATA_D_MEDIA_CHANGED;
fdp->disk->d_sectorsize = fdp->cap.sector_size;
fdp->disk->d_mediasize = (off_t)fdp->cap.sector_size * fdp->cap.sectors *
fdp->cap.heads * fdp->cap.cylinders;
fdp->disk->d_fwsectors = fdp->cap.sectors;
fdp->disk->d_fwheads = fdp->cap.heads;
return 0;
}
static int
afd_sense(struct afd_softc *fdp)
afd_close(struct disk *dp)
{
device_t dev = dp->d_drv1;
afd_prevent_allow(dev, 0);
return 0;
}
static void
afd_strategy(struct bio *bp)
{
device_t dev = bp->bio_disk->d_drv1;
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp = device_get_ivars(dev);
struct ata_request *request;
u_int16_t count;
int8_t ccb[16];
/* if it's a null transfer, return immediatly. */
if (bp->bio_bcount == 0) {
bp->bio_resid = 0;
biodone(bp);
return;
}
/* should reject all queued entries if media have changed. */
if (atadev->flags & ATA_D_MEDIA_CHANGED) {
biofinish(bp, NULL, EIO);
return;
}
count = bp->bio_bcount / fdp->cap.sector_size;
bp->bio_resid = bp->bio_bcount;
bzero(ccb, sizeof(ccb));
if (bp->bio_cmd == BIO_READ)
ccb[0] = ATAPI_READ_BIG;
else
ccb[0] = ATAPI_WRITE_BIG;
ccb[2] = bp->bio_pblkno >> 24;
ccb[3] = bp->bio_pblkno >> 16;
ccb[4] = bp->bio_pblkno >> 8;
ccb[5] = bp->bio_pblkno;
ccb[7] = count>>8;
ccb[8] = count;
if (!(request = ata_alloc_request())) {
biofinish(bp, NULL, ENOMEM);
return;
}
request->dev = dev;
request->bio = bp;
bcopy(ccb, request->u.atapi.ccb,
(atadev->param.config & ATA_PROTO_MASK) ==
ATA_PROTO_ATAPI_12 ? 16 : 12);
request->data = bp->bio_data;
request->bytecount = count * fdp->cap.sector_size;
request->transfersize = min(request->bytecount, 65534);
request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30;
request->retries = 2;
request->callback = afd_done;
switch (bp->bio_cmd) {
case BIO_READ:
request->flags = (ATA_R_ATAPI | ATA_R_READ);
break;
case BIO_WRITE:
request->flags = (ATA_R_ATAPI | ATA_R_WRITE);
break;
default:
device_printf(dev, "unknown BIO operation\n");
ata_free_request(request);
biofinish(bp, NULL, EIO);
return;
}
if (atadev->mode >= ATA_DMA)
request->flags |= ATA_R_DMA;
request->flags |= ATA_R_ORDERED;
ata_queue_request(request);
}
static void
afd_done(struct ata_request *request)
{
struct bio *bp = request->bio;
/* finish up transfer */
if ((bp->bio_error = request->result))
bp->bio_flags |= BIO_ERROR;
bp->bio_resid = bp->bio_bcount - request->donecount;
biodone(bp);
ata_free_request(request);
}
static int
afd_sense(device_t dev)
{
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp = device_get_ivars(dev);
int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
int count;
/* The IOMEGA Clik! doesn't support reading the cap page, fake it */
if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
if (!strncmp(atadev->param.model, "IOMEGA Clik!", 12)) {
fdp->cap.transfer_rate = 500;
fdp->cap.heads = 1;
fdp->cap.sectors = 2;
fdp->cap.cylinders = 39441;
fdp->cap.sector_size = 512;
afd_test_ready(fdp->device);
afd_test_ready(dev);
return 0;
}
/* get drive capabilities, some bugridden drives needs this repeated */
for (count = 0 ; count < 5 ; count++) {
if (!ata_atapicmd(fdp->device, ccb, (caddr_t)&fdp->cap,
if (!ata_atapicmd(atadev, ccb, (caddr_t)&fdp->cap,
sizeof(struct afd_cappage), ATA_R_READ, 30) &&
fdp->cap.page_code == ATAPI_REWRITEABLE_CAP_PAGE) {
fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
@ -170,26 +324,51 @@ afd_sense(struct afd_softc *fdp)
return 1;
}
static void
afd_describe(struct afd_softc *fdp)
static int
afd_prevent_allow(device_t dev, int lock)
{
struct ata_device *atadev = device_get_softc(dev);
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
if (!strncmp(atadev->param.model, "IOMEGA Clik!", 12))
return 0;
return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
}
static int
afd_test_ready(device_t dev)
{
struct ata_device *atadev = device_get_softc(dev);
int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
}
static void
afd_describe(device_t dev)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
struct afd_softc *fdp = device_get_ivars(dev);
if (bootverbose) {
ata_prtdev(fdp->device,
"<%.40s/%.8s> removable drive at ata%d as %s\n",
fdp->device->param->model, fdp->device->param->revision,
device_get_unit(fdp->device->channel->dev),
(fdp->device->unit == ATA_MASTER) ? "master" : "slave");
ata_prtdev(fdp->device,
"%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
(fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
((1024L * 1024L) / fdp->cap.sector_size),
fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
fdp->cap.sector_size);
ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8);
printf(" %s\n", ata_mode2str(fdp->device->mode));
device_printf(dev, "<%.40s/%.8s> removable drive at ata%d as %s\n",
atadev->param.model, atadev->param.revision,
device_get_unit(ch->dev),
(atadev->unit == ATA_MASTER) ? "master" : "slave");
device_printf(dev,
"%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
(fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
((1024L * 1024L) / fdp->cap.sector_size),
fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
fdp->cap.sector_size);
device_printf(dev, "%dKB/s,", fdp->cap.transfer_rate / 8);
printf(" %s\n", ata_mode2str(atadev->mode));
if (fdp->cap.medium_type) {
ata_prtdev(fdp->device, "Medium: ");
device_printf(dev, "Medium: ");
switch (fdp->cap.medium_type) {
case MFD_2DD:
printf("720KB DD disk"); break;
@ -211,234 +390,53 @@ afd_describe(struct afd_softc *fdp)
}
}
else {
ata_prtdev(fdp->device, "REMOVABLE <%.40s/%.8s> at ata%d-%s %s\n",
fdp->device->param->model, fdp->device->param->revision,
device_get_unit(fdp->device->channel->dev),
(fdp->device->unit == ATA_MASTER) ? "master" : "slave",
ata_mode2str(fdp->device->mode));
device_printf(dev, "REMOVABLE <%.40s/%.8s> at ata%d-%s %s\n",
atadev->param.model, atadev->param.revision,
device_get_unit(ch->dev),
(atadev->unit == ATA_MASTER) ? "master" : "slave",
ata_mode2str(atadev->mode));
}
}
static int
afd_open(struct disk *dp)
{
struct afd_softc *fdp = dp->d_drv1;
if (fdp->device->flags & ATA_D_DETACHING)
return ENXIO;
afd_test_ready(fdp->device);
afd_prevent_allow(fdp, 1);
if (afd_sense(fdp))
ata_prtdev(fdp->device, "sense media type failed\n");
fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
fdp->disk->d_sectorsize = fdp->cap.sector_size;
fdp->disk->d_mediasize = (off_t)fdp->cap.sector_size * fdp->cap.sectors *
fdp->cap.heads * fdp->cap.cylinders;
fdp->disk->d_fwsectors = fdp->cap.sectors;
fdp->disk->d_fwheads = fdp->cap.heads;
return 0;
}
static int
afd_close(struct disk *dp)
{
struct afd_softc *fdp = dp->d_drv1;
afd_prevent_allow(fdp, 0);
if (0)
afd_eject(fdp, 0); /* to keep gcc quiet */
return 0;
}
#ifdef notyet
static int
afd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
{
struct afd_softc *fdp = dp->d_drv1;
switch (cmd) {
case CDIOCEJECT:
if (count_dev(dev) > 1)
return EBUSY;
return afd_eject(fdp, 0);
case CDIOCCLOSE:
if (count_dev(dev) > 1)
return 0;
return afd_eject(fdp, 1);
default:
return ENOIOCTL;
}
}
#endif
static void
afdstrategy(struct bio *bp)
{
struct afd_softc *fdp = bp->bio_disk->d_drv1;
if (fdp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
return;
}
/* if it's a null transfer, return immediatly. */
if (bp->bio_bcount == 0) {
bp->bio_resid = 0;
biodone(bp);
return;
}
mtx_lock(&fdp->queue_mtx);
bioq_disksort(&fdp->queue, bp);
mtx_unlock(&fdp->queue_mtx);
ata_start(fdp->device->channel);
}
static void
afd_start(struct ata_device *atadev)
{
struct afd_softc *fdp = atadev->softc;
struct bio *bp;
struct ata_request *request;
u_int32_t lba;
u_int16_t count;
int8_t ccb[16];
mtx_lock(&fdp->queue_mtx);
bp = bioq_first(&fdp->queue);
if (!bp) {
mtx_unlock(&fdp->queue_mtx);
return;
}
bioq_remove(&fdp->queue, bp);
mtx_unlock(&fdp->queue_mtx);
/* should reject all queued entries if media have changed. */
if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
biofinish(bp, NULL, EIO);
return;
}
lba = bp->bio_pblkno;
count = bp->bio_bcount / fdp->cap.sector_size;
bp->bio_resid = bp->bio_bcount;
bzero(ccb, sizeof(ccb));
if (bp->bio_cmd == BIO_READ)
ccb[0] = ATAPI_READ_BIG;
else
ccb[0] = ATAPI_WRITE_BIG;
ccb[2] = lba>>24;
ccb[3] = lba>>16;
ccb[4] = lba>>8;
ccb[5] = lba;
ccb[7] = count>>8;
ccb[8] = count;
if (!(request = ata_alloc_request())) {
biofinish(bp, NULL, ENOMEM);
return;
}
request->device = atadev;
request->driver = bp;
bcopy(ccb, request->u.atapi.ccb,
(request->device->param->config & ATA_PROTO_MASK) ==
ATA_PROTO_ATAPI_12 ? 16 : 12);
request->data = bp->bio_data;
request->bytecount = count * fdp->cap.sector_size;
request->transfersize = min(request->bytecount, 65534);
request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30;
request->retries = 2;
request->callback = afd_done;
switch (bp->bio_cmd) {
case BIO_READ:
request->flags |= (ATA_R_ATAPI | ATA_R_READ);
break;
case BIO_WRITE:
request->flags |= (ATA_R_ATAPI | ATA_R_WRITE);
break;
default:
ata_prtdev(atadev, "unknown BIO operation\n");
ata_free_request(request);
biofinish(bp, NULL, EIO);
return;
}
ata_queue_request(request);
}
static void
afd_done(struct ata_request *request)
{
struct bio *bp = request->driver;
/* finish up transfer */
if ((bp->bio_error = request->result))
bp->bio_flags |= BIO_ERROR;
bp->bio_resid = bp->bio_bcount - request->donecount;
biodone(bp);
ata_free_request(request);
}
static int
afd_eject(struct afd_softc *fdp, int close)
{
int error;
if ((error = afd_start_stop(fdp, 0)) == EBUSY) {
if (!close)
return 0;
if ((error = afd_start_stop(fdp, 3)))
return error;
return afd_prevent_allow(fdp, 1);
}
if (error)
return error;
if (close)
return 0;
if ((error = afd_prevent_allow(fdp, 0)))
return error;
fdp->device->flags |= ATA_D_MEDIA_CHANGED;
return afd_start_stop(fdp, 2);
}
static int
afd_start_stop(struct afd_softc *fdp, int start)
{
int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30);
}
static int
afd_prevent_allow(struct afd_softc *fdp, int lock)
{
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static device_method_t afd_methods[] = {
/* device interface */
DEVMETHOD(device_identify, afd_identify),
DEVMETHOD(device_probe, afd_probe),
DEVMETHOD(device_attach, afd_attach),
DEVMETHOD(device_detach, afd_detach),
DEVMETHOD(device_shutdown, afd_shutdown),
if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
return 0;
return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30);
}
/* ATA methods */
DEVMETHOD(ata_reinit, afd_reinit),
{ 0, 0 }
};
static driver_t afd_driver = {
"afd",
afd_methods,
sizeof(struct afd_softc)
};
static devclass_t afd_devclass;
static int
afd_test_ready(struct ata_device *atadev)
afd_modevent(module_t mod, int what, void *arg)
{
int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
device_t *devs;
int ndevs, i;
return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
if (what == MOD_UNLOAD) {
if (!devclass_get_devices(afd_devclass, &devs, &ndevs) && devs) {
for (i = 0; i < ndevs; i++)
device_delete_child(device_get_parent(devs[i]), devs[i]);
free(devs, M_TEMP);
}
}
return 0;
}
DRIVER_MODULE(afd, ata, afd_driver, afd_devclass, afd_modevent, NULL);
MODULE_VERSION(afd, 1);
MODULE_DEPEND(afd, ata, 1, 1, 1);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,50 +30,46 @@
/* ATAPI Rewriteable drive Capabilities and Mechanical Status Page */
struct afd_cappage {
u_int16_t data_length;
u_int8_t medium_type;
#define MFD_2DD_UN 0x10
#define MFD_2DD 0x11
#define MFD_HD_UN 0x20
#define MFD_HD_12_98 0x22
#define MFD_HD_12 0x23
#define MFD_HD_144 0x24
#define MFD_UHD 0x31
u_int16_t data_length;
u_int8_t medium_type;
#define MFD_2DD_UN 0x10
#define MFD_2DD 0x11
#define MFD_HD_UN 0x20
#define MFD_HD_12_98 0x22
#define MFD_HD_12 0x23
#define MFD_HD_144 0x24
#define MFD_UHD 0x31
#define MFD_UNKNOWN 0x00
#define MFD_NO_DISC 0x70
#define MFD_DOOR_OPEN 0x71
#define MFD_FMT_ERROR 0x72
#define MFD_UNKNOWN 0x00
#define MFD_NO_DISC 0x70
#define MFD_DOOR_OPEN 0x71
#define MFD_FMT_ERROR 0x72
u_int8_t reserved0 :7;
u_int8_t wp :1; /* write protect */
u_int8_t unused[4];
u_int8_t reserved0 :7;
u_int8_t wp :1; /* write protect */
u_int8_t unused[4];
/* capabilities page */
u_int8_t page_code :6;
#define ATAPI_REWRITEABLE_CAP_PAGE 0x05
u_int8_t page_code :6;
#define ATAPI_REWRITEABLE_CAP_PAGE 0x05
u_int8_t reserved1_6 :1;
u_int8_t ps :1; /* page save supported */
u_int8_t page_length; /* page length */
u_int16_t transfer_rate; /* in kilobits per second */
u_int8_t heads; /* number of heads */
u_int8_t sectors; /* number of sectors pr track */
u_int16_t sector_size; /* number of bytes per sector */
u_int16_t cylinders; /* number of cylinders */
u_int8_t reserved10[10];
u_int8_t motor_delay; /* motor off delay */
u_int8_t reserved21[7];
u_int16_t rpm; /* rotations per minute */
u_int8_t reserved30[2];
u_int8_t reserved1_6 :1;
u_int8_t ps :1; /* page save supported */
u_int8_t page_length; /* page length */
u_int16_t transfer_rate; /* in kilobits per second */
u_int8_t heads; /* number of heads */
u_int8_t sectors; /* number of sectors pr track */
u_int16_t sector_size; /* number of bytes per sector */
u_int16_t cylinders; /* number of cylinders */
u_int8_t reserved10[10];
u_int8_t motor_delay; /* motor off delay */
u_int8_t reserved21[7];
u_int16_t rpm; /* rotations per minute */
u_int8_t reserved30[2];
};
struct afd_softc {
struct ata_device *device; /* device softc */
int lun; /* logical device unit */
struct mtx queue_mtx; /* bio queue lock */
struct bio_queue_head queue; /* queue of i/o requests */
struct afd_cappage cap; /* capabilities page info */
struct disk *disk; /* virtual drives */
struct afd_cappage cap; /* capabilities page info */
struct disk *disk; /* virtual drives */
};

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 1998 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 1998 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,133 +31,129 @@
/* ATAPI tape drive Capabilities and Mechanical Status Page */
struct ast_cappage {
/* mode page data header */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t reserved :4;
u_int8_t mode :3; /* buffering mode */
u_int8_t write_protect :1; /* media is writeprotected */
u_int8_t blk_desc_len; /* block Descriptor Length */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t reserved :4;
u_int8_t mode :3; /* buffering mode */
u_int8_t write_protect :1; /* media is writeprotected */
u_int8_t blk_desc_len; /* block Descriptor Length */
/* capabilities page */
u_int8_t page_code :6;
#define ATAPI_TAPE_CAP_PAGE 0x2a
u_int8_t page_code :6;
#define ATAPI_TAPE_CAP_PAGE 0x2a
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x12 */
u_int8_t reserved2;
u_int8_t reserved3;
u_int8_t readonly :1; /* read Only Mode */
u_int8_t reserved4_1234 :4;
u_int8_t reverse :1; /* supports reverse direction */
u_int8_t reserved4_67 :2;
u_int8_t reserved5_012 :3;
u_int8_t eformat :1; /* supports ERASE formatting */
u_int8_t reserved5_4 :1;
u_int8_t qfa :1; /* supports QFA formats */
u_int8_t reserved5_67 :2;
u_int8_t lock :1; /* supports locking media */
u_int8_t locked :1; /* the media is locked */
u_int8_t prevent :1; /* defaults to prevent state */
u_int8_t eject :1; /* supports eject */
u_int8_t disconnect :1; /* can break request > ctl */
u_int8_t reserved6_5 :1;
u_int8_t ecc :1; /* supports error correction */
u_int8_t compress :1; /* supports data compression */
u_int8_t reserved7_0 :1;
u_int8_t blk512 :1; /* supports 512b block size */
u_int8_t blk1024 :1; /* supports 1024b block size */
u_int8_t reserved7_3456 :4;
u_int8_t blk32k :1; /* supports 32kb block size */
u_int16_t max_speed; /* supported speed in KBps */
u_int16_t max_defects; /* max stored defect entries */
u_int16_t ctl; /* continuous transfer limit */
u_int16_t speed; /* current Speed, in KBps */
u_int16_t buffer_size; /* buffer Size, in 512 bytes */
u_int8_t reserved18;
u_int8_t reserved19;
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x12 */
u_int8_t reserved2;
u_int8_t reserved3;
u_int8_t readonly :1; /* read Only Mode */
u_int8_t reserved4_1234 :4;
u_int8_t reverse :1; /* supports reverse direction */
u_int8_t reserved4_67 :2;
u_int8_t reserved5_012 :3;
u_int8_t eformat :1; /* supports ERASE formatting */
u_int8_t reserved5_4 :1;
u_int8_t qfa :1; /* supports QFA formats */
u_int8_t reserved5_67 :2;
u_int8_t lock :1; /* supports locking media */
u_int8_t locked :1; /* the media is locked */
u_int8_t prevent :1; /* defaults to prevent state */
u_int8_t eject :1; /* supports eject */
u_int8_t disconnect :1; /* can break request > ctl */
u_int8_t reserved6_5 :1;
u_int8_t ecc :1; /* supports error correction */
u_int8_t compress :1; /* supports data compression */
u_int8_t reserved7_0 :1;
u_int8_t blk512 :1; /* supports 512b block size */
u_int8_t blk1024 :1; /* supports 1024b block size */
u_int8_t reserved7_3456 :4;
u_int8_t blk32k :1; /* supports 32kb block size */
u_int16_t max_speed; /* supported speed in KBps */
u_int16_t max_defects; /* max stored defect entries */
u_int16_t ctl; /* continuous transfer limit */
u_int16_t speed; /* current Speed, in KBps */
u_int16_t buffer_size; /* buffer Size, in 512 bytes */
u_int8_t reserved18;
u_int8_t reserved19;
};
/* ATAPI OnStream ADR data transfer mode page (ADR unique) */
struct ast_transferpage {
/* mode page data header */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t dsp; /* device specific parameter */
u_int8_t blk_desc_len; /* block Descriptor Length */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t dsp; /* device specific parameter */
u_int8_t blk_desc_len; /* block Descriptor Length */
/* data transfer page */
u_int8_t page_code :6;
u_int8_t page_code :6;
#define ATAPI_TAPE_TRANSFER_PAGE 0x30
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x02 */
u_int8_t reserved2;
u_int8_t read32k :1; /* 32k blk size (data only) */
u_int8_t read32k5 :1; /* 32.5k blk size (data&AUX) */
u_int8_t reserved3_23 :2;
u_int8_t write32k :1; /* 32k blk size (data only) */
u_int8_t write32k5 :1; /* 32.5k blk size (data&AUX) */
u_int8_t reserved3_6 :1;
u_int8_t streaming :1; /* streaming mode enable */
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x02 */
u_int8_t reserved2;
u_int8_t read32k :1; /* 32k blk size (data only) */
u_int8_t read32k5 :1; /* 32.5k blk size (data&AUX) */
u_int8_t reserved3_23 :2;
u_int8_t write32k :1; /* 32k blk size (data only) */
u_int8_t write32k5 :1; /* 32.5k blk size (data&AUX) */
u_int8_t reserved3_6 :1;
u_int8_t streaming :1; /* streaming mode enable */
};
/* ATAPI OnStream ADR vendor identification mode page (ADR unique) */
struct ast_identifypage {
/* mode page data header */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t dsp; /* device specific parameter */
u_int8_t blk_desc_len; /* block Descriptor Length */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t dsp; /* device specific parameter */
u_int8_t blk_desc_len; /* block Descriptor Length */
/* data transfer page */
u_int8_t page_code :6;
u_int8_t page_code :6;
#define ATAPI_TAPE_IDENTIFY_PAGE 0x36
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x06 */
u_int8_t ident[4]; /* host id string */
u_int8_t reserved6;
u_int8_t reserved7;
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x06 */
u_int8_t ident[4]; /* host id string */
u_int8_t reserved6;
u_int8_t reserved7;
};
/* ATAPI read position structure */
struct ast_readposition {
u_int8_t reserved0_05 :6;
u_int8_t eop :1; /* end of partition */
u_int8_t bop :1; /* beginning of partition */
u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t reserved3;
u_int32_t host; /* frame address in buffer */
u_int32_t tape; /* frame address on tape */
u_int8_t reserved12;
u_int8_t reserved13;
u_int8_t reserved14;
u_int8_t blks_in_buf; /* blocks in buffer */
u_int8_t reserved16;
u_int8_t reserved17;
u_int8_t reserved18;
u_int8_t reserved19;
u_int8_t reserved0_05 :6;
u_int8_t eop :1; /* end of partition */
u_int8_t bop :1; /* beginning of partition */
u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t reserved3;
u_int32_t host; /* frame address in buffer */
u_int32_t tape; /* frame address on tape */
u_int8_t reserved12;
u_int8_t reserved13;
u_int8_t reserved14;
u_int8_t blks_in_buf; /* blocks in buffer */
u_int8_t reserved16;
u_int8_t reserved17;
u_int8_t reserved18;
u_int8_t reserved19;
};
struct ast_softc {
struct ata_device *device; /* device softc */
int lun; /* logical device unit */
int flags; /* device state flags */
#define F_CTL_WARN 0x0001 /* warned about CTL wrong? */
#define F_WRITEPROTECT 0x0002 /* media is writeprotected */
#define F_DATA_WRITTEN 0x0004 /* data has been written */
#define F_FM_WRITTEN 0x0008 /* filemark has been written */
#define F_ONSTREAM 0x0100 /* OnStream ADR device */
int flags; /* device state flags */
#define F_CTL_WARN 0x0001 /* warned about CTL wrong? */
#define F_WRITEPROTECT 0x0002 /* media is writeprotected */
#define F_DATA_WRITTEN 0x0004 /* data has been written */
#define F_FM_WRITTEN 0x0008 /* filemark has been written */
#define F_ONSTREAM 0x0100 /* OnStream ADR device */
int blksize; /* block size (512 | 1024) */
struct mtx queue_mtx; /* bio queue lock */
struct bio_queue_head queue; /* queue of i/o requests */
struct atapi_params *param; /* drive parameters table */
struct ast_cappage cap; /* capabilities page info */
struct devstat *stats; /* devstat entry */
struct cdev *dev1, *dev2; /* device place holders */
int blksize; /* block size (512 | 1024) */
struct atapi_params *param; /* drive parameters table */
struct ast_cappage cap; /* capabilities page info */
struct devstat *stats; /* devstat entry */
struct cdev *dev1, *dev2; /* device place holders */
};

View File

@ -23,6 +23,7 @@ SUBDIR= ${_3dfx} \
${_arcnet} \
${_arl} \
${_asr} \
ata \
ath \
${_ath_hal} \
ath_rate_amrr \

13
sys/modules/ata/Makefile Normal file
View File

@ -0,0 +1,13 @@
# $FreeBSD$
SUBDIR = ata
SUBDIR += atacard
.if ${MACHINE} == "pc98"
SUBDIR += atacbus
.else
SUBDIR += ataisa
.endif
SUBDIR += atapci
SUBDIR += atadisk atapicd atapifd atapist ataraid #atacam
.include <bsd.subdir.mk>

View File

@ -0,0 +1,3 @@
# $FreeBSD$
.include "../Makefile.inc"

View File

@ -0,0 +1,10 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= ata
SRCS= ata-all.c ata-queue.c ata-lowlevel.c ata_if.c
# ata-pci.c ata-dma.c ata-chipset.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atacam
SRCS= ata-cam.c
SRCS+= opt_ata.h opt_cam.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atacard
SRCS= ata-card.c
SRCS+= opt_ata.h pccarddevs.h ata_if.h device_if.h bus_if.h isa_if.h card_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atacbus
SRCS= ata-cbus.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h isa_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atadisk
SRCS= ata-disk.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= ataisa
SRCS= ata-isa.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h isa_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atapci
SRCS= ata-pci.c ata-dma.c ata-chipset.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atapicd
SRCS= atapi-cd.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atapifd
SRCS= atapi-fd.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= atapist
SRCS= atapi-tape.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ata
KMOD= ataraid
SRCS= ata-raid.c
SRCS+= opt_ata.h ata_if.h device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000 - 2004 Søren Schmidt <sos@FreeBSD.org>
* Copyright (c) 2000 - 2005 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -37,7 +37,7 @@
struct ata_params {
/*000*/ u_int16_t config; /* configuration info */
#define ATA_PROTO_MASK 0x8003
#define ATA_PROTO_ATA 0x0002
#define ATA_PROTO_ATA 0x0000
#define ATA_PROTO_ATAPI_12 0x8000
#define ATA_PROTO_ATAPI_16 0x8001
#define ATA_ATAPI_TYPE_MASK 0x1f00
@ -82,7 +82,11 @@ struct ata_params {
#define ATA_FLAG_64_70 0x0002 /* words 64-70 valid */
#define ATA_FLAG_88 0x0004 /* word 88 valid */
/*054*/ u_int16_t obsolete54[5];
/*054*/ u_int16_t current_cylinders;
/*055*/ u_int16_t current_heads;
/*056*/ u_int16_t current_sectors;
/*057*/ u_int16_t current_size_1;
/*058*/ u_int16_t current_size_2;
/*059*/ u_int16_t multi;
#define ATA_MULTI_VALID 0x0100
@ -155,7 +159,7 @@ struct ata_params {
#define ATA_SUPPORT_FLUSHCACHE48 0x2000
/*084/087*/ u_int16_t extension;
} support, enabled;
} __packed support, enabled;
/*088*/ u_int16_t udmamodes; /* UltraDMA modes */
/*089*/ u_int16_t erase_time;
@ -182,11 +186,11 @@ struct ata_params {
/*128*/ u_int16_t security_status;
u_int16_t reserved129[31];
/*160*/ u_int16_t cfa_powermode1;
u_int16_t reserved161[14];
u_int16_t reserved161[15];
/*176*/ u_int16_t media_serial[30];
u_int16_t reserved206[49];
/*255*/ u_int16_t integrity;
};
} __packed;
/* ATA transfer modes */
#define ATA_MODE_MASK 0x0f
@ -368,9 +372,14 @@ struct ata_cmd {
struct raid_setup {
int type;
#define AR_RAID0 1
#define AR_RAID1 2
#define AR_SPAN 4
#define AR_JBOD 0x01
#define AR_SPAN 0x02
#define AR_RAID0 0x04
#define AR_RAID1 0x08
#define AR_RAID01 0x10
#define AR_RAID3 0x20
#define AR_RAID4 0x40
#define AR_RAID5 0x80
int total_disks;
int disks[16];