diff options
author | sos <sos@FreeBSD.org> | 2008-04-10 13:05:05 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2008-04-10 13:05:05 +0000 |
commit | 34ad2308146bd2683968373b3f427e50e7dbe7c6 (patch) | |
tree | f3e7a479de8c6c0f0f0f4fe2f5fd2f056d3b80be /sys | |
parent | 8f080cfa2b4b4a38cdc320c3d842360c2a61f1c3 (diff) | |
download | FreeBSD-src-34ad2308146bd2683968373b3f427e50e7dbe7c6.zip FreeBSD-src-34ad2308146bd2683968373b3f427e50e7dbe7c6.tar.gz |
Add experimental support for SATA Port Multipliers
Support is working on the Silicon Image SiI3124/3132.
Support is working on some AHCI chips but far from all.
Remember this is WIP, so test reports and (constructive) suggestions are welcome!
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ata/ata-all.c | 130 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 67 | ||||
-rw-r--r-- | sys/dev/ata/ata-card.c | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-cbus.c | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-chipset.c | 1063 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 165 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.h | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-dma.c | 288 | ||||
-rw-r--r-- | sys/dev/ata/ata-isa.c | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-lowlevel.c | 64 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.c | 81 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.h | 3 | ||||
-rw-r--r-- | sys/dev/ata/ata-queue.c | 11 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.c | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.h | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-usb.c | 3 | ||||
-rw-r--r-- | sys/dev/ata/ata_if.m | 2 | ||||
-rw-r--r-- | sys/dev/ata/atapi-cd.c | 13 | ||||
-rw-r--r-- | sys/dev/ata/atapi-cd.h | 2 | ||||
-rw-r--r-- | sys/dev/ata/atapi-fd.c | 10 | ||||
-rw-r--r-- | sys/dev/ata/atapi-fd.h | 2 | ||||
-rw-r--r-- | sys/dev/ata/atapi-tape.c | 18 | ||||
-rw-r--r-- | sys/dev/ata/atapi-tape.h | 2 | ||||
-rw-r--r-- | sys/sys/ata.h | 8 |
24 files changed, 1296 insertions, 648 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index e275b6a..2f1f317 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,7 +62,6 @@ static struct cdevsw ata_cdevsw = { /* prototypes */ static void ata_boot_attach(void); static device_t ata_add_child(device_t, struct ata_device *, int); -static int ata_getparam(struct ata_device *, int); static void bswap(int8_t *, int); static void btrim(int8_t *, int); static void bpack(int8_t *, int8_t *, int); @@ -75,6 +74,7 @@ devclass_t ata_devclass; uma_zone_t ata_request_zone; uma_zone_t ata_composite_zone; int ata_wc = 1; +int ata_setmax = 0; /* local vars */ static int ata_dma = 1; @@ -91,6 +91,9 @@ SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RDTUN, &atapi_dma, 0, TUNABLE_INT("hw.ata.wc", &ata_wc); SYSCTL_INT(_hw_ata, OID_AUTO, wc, CTLFLAG_RDTUN, &ata_wc, 0, "ATA disk write caching"); +TUNABLE_INT("hw.ata.setmax", &ata_setmax); +SYSCTL_INT(_hw_ata, OID_AUTO, setmax, CTLFLAG_RDTUN, &ata_setmax, 0, + "ATA disk set max native address"); /* * newbus device interface related functions @@ -404,13 +407,13 @@ ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data, if (children[i] && device_is_attached(children[i])) { struct ata_device *atadev = device_get_softc(children[i]); - if (atadev->unit == ATA_MASTER) { + if (atadev->unit == ATA_MASTER) { /* XXX SOS PM */ strncpy(devices->name[0], device_get_nameunit(children[i]), 32); bcopy(&atadev->param, &devices->params[0], sizeof(struct ata_params)); } - if (atadev->unit == ATA_SLAVE) { + if (atadev->unit == ATA_SLAVE) { /* XXX SOS PM */ strncpy(devices->name[1], device_get_nameunit(children[i]), 32); bcopy(&atadev->param, &devices->params[1], @@ -569,7 +572,7 @@ ata_add_child(device_t parent, struct ata_device *atadev, int unit) return child; } -static int +int ata_getparam(struct ata_device *atadev, int init) { struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); @@ -577,11 +580,9 @@ ata_getparam(struct ata_device *atadev, int init) u_int8_t command = 0; int error = ENOMEM, retries = 2; - if (ch->devices & - (atadev->unit == ATA_MASTER ? ATA_ATA_MASTER : ATA_ATA_SLAVE)) + if (ch->devices & (ATA_ATA_MASTER << atadev->unit)) command = ATA_ATA_IDENTIFY; - if (ch->devices & - (atadev->unit == ATA_MASTER ? ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE)) + if (ch->devices & (ATA_ATAPI_MASTER << atadev->unit)) command = ATA_ATAPI_IDENTIFY; if (!command) return ENXIO; @@ -631,7 +632,7 @@ ata_getparam(struct ata_device *atadev, int init) if (bootverbose) printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n", device_get_unit(ch->dev), - atadev->unit == ATA_MASTER ? "master" : "slave", + ata_unit2str(atadev), ata_mode2str(ata_pmode(atacap)), ata_mode2str(ata_wmode(atacap)), ata_mode2str(ata_umode(atacap)), @@ -643,13 +644,13 @@ ata_getparam(struct ata_device *atadev, int init) if ((atadev->param.config & ATA_PROTO_ATAPI) && (atadev->param.config != ATA_CFA_MAGIC1) && (atadev->param.config != ATA_CFA_MAGIC2)) { - if (atapi_dma && ch->dma && + if (atapi_dma && (atadev->param.config & ATA_DRQ_MASK) != ATA_DRQ_INTR && ata_umode(&atadev->param) >= ATA_UDMA2) atadev->mode = ATA_DMA_MAX; } else { - if (ata_dma && ch->dma && + if (ata_dma && (ata_umode(&atadev->param) > 0 || ata_wmode(&atadev->param) > 0)) atadev->mode = ATA_DMA_MAX; @@ -667,52 +668,39 @@ int ata_identify(device_t dev) { struct ata_channel *ch = device_get_softc(dev); - struct ata_device *master = NULL, *slave = NULL; - device_t master_child = NULL, slave_child = NULL; - int master_unit = -1, slave_unit = -1; - - if (ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) { - if (!(master = malloc(sizeof(struct ata_device), - M_ATA, M_NOWAIT | M_ZERO))) { - device_printf(dev, "out of memory\n"); - return ENOMEM; - } - master->unit = ATA_MASTER; - } - if (ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) { - if (!(slave = malloc(sizeof(struct ata_device), - M_ATA, M_NOWAIT | M_ZERO))) { - free(master, M_ATA); - device_printf(dev, "out of memory\n"); - return ENOMEM; - } - slave->unit = ATA_SLAVE; - } + struct ata_device *devices[ATA_PM]; + device_t childdevs[ATA_PM]; + int i, unit = -1; + if (bootverbose) + device_printf(dev, "identify ch->devices=%08x\n", ch->devices); + + for (i = 0; i < ATA_PM; ++i) { + if (ch->devices & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i))) { + if (!(devices[i] = malloc(sizeof(struct ata_device), + M_ATA, M_NOWAIT | M_ZERO))) { + device_printf(dev, "out of memory\n"); + return ENOMEM; + } + devices[i]->unit = i; #ifdef ATA_STATIC_ID - if (ch->devices & ATA_ATA_MASTER) - master_unit = (device_get_unit(dev) << 1); -#endif - if (master && !(master_child = ata_add_child(dev, master, master_unit))) { - free(master, M_ATA); - master = NULL; - } -#ifdef ATA_STATIC_ID - if (ch->devices & ATA_ATA_SLAVE) - slave_unit = (device_get_unit(dev) << 1) + 1; + unit = (device_get_unit(dev) << 1) + i; #endif - if (slave && !(slave_child = ata_add_child(dev, slave, slave_unit))) { - free(slave, M_ATA); - slave = NULL; - } - - if (slave && ata_getparam(slave, 1)) { - device_delete_child(dev, slave_child); - free(slave, M_ATA); - } - if (master && ata_getparam(master, 1)) { - device_delete_child(dev, master_child); - free(master, M_ATA); + if (!(childdevs[i] = ata_add_child(dev, devices[i], unit))) { + free(devices[i], M_ATA); + devices[i]=NULL; + } + else { + if (ata_getparam(devices[i], 1)) { + device_delete_child(dev, childdevs[i]); + free(devices[i], M_ATA); + childdevs[i] = NULL; + devices[i] = NULL; + } + } + } + devices[i] = NULL; + childdevs[i] = NULL; } bus_generic_probe(dev); @@ -810,8 +798,23 @@ ata_modify_if_48bit(struct ata_request *request) case ATA_FLUSHCACHE: request->u.ata.command = ATA_FLUSHCACHE48; break; - case ATA_READ_NATIVE_MAX_ADDDRESS: - request->u.ata.command = ATA_READ_NATIVE_MAX_ADDDRESS48; + case ATA_SET_MAX_ADDRESS: + request->u.ata.command = ATA_SET_MAX_ADDRESS48; + break; + default: + return; + } + atadev->flags |= ATA_D_48BIT_ACTIVE; + } + else if (atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { + + /* translate command into 48bit version */ + switch (request->u.ata.command) { + case ATA_FLUSHCACHE: + request->u.ata.command = ATA_FLUSHCACHE48; + break; + case ATA_READ_NATIVE_MAX_ADDRESS: + request->u.ata.command = ATA_READ_NATIVE_MAX_ADDRESS48; break; case ATA_SET_MAX_ADDRESS: request->u.ata.command = ATA_SET_MAX_ADDRESS48; @@ -834,6 +837,19 @@ ata_udelay(int interval) } char * +ata_unit2str(struct ata_device *atadev) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); + static char str[8]; + + if (ch->devices & ATA_PORTMULTIPLIER) + sprintf(str, "port%d", atadev->unit); + else + sprintf(str, "%s", atadev->unit == ATA_MASTER ? "master" : "slave"); + return str; +} + +char * ata_mode2str(int mode) { switch (mode) { diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 28adac9..6470e35 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -149,6 +149,7 @@ /* SATA AHCI v1.0 register defines */ #define ATA_AHCI_CAP 0x00 #define ATA_AHCI_NPMASK 0x1f +#define ATA_AHCI_CAP_SPM 0x00020000 #define ATA_AHCI_CAP_CLO 0x01000000 #define ATA_AHCI_CAP_64BIT 0x80000000 @@ -220,11 +221,13 @@ #define ATA_AHCI_P_SERR 0x130 #define ATA_AHCI_P_SACT 0x134 #define ATA_AHCI_P_CI 0x138 +#define ATA_AHCI_P_SNTF 0x13C +#define ATA_AHCI_P_FBS 0x140 #define ATA_AHCI_CL_SIZE 32 #define ATA_AHCI_CL_OFFSET 0 #define ATA_AHCI_FB_OFFSET 1024 -#define ATA_AHCI_CT_OFFSET 1024+256 +#define ATA_AHCI_CT_OFFSET 1024+4096 #define ATA_AHCI_CT_SG_OFFSET 128 #define ATA_AHCI_CT_SIZE 256 @@ -245,6 +248,13 @@ struct ata_ahci_cmd_tab { struct ata_ahci_cmd_list { u_int16_t cmd_flags; +#define ATA_AHCI_CMD_ATAPI 0x0020 +#define ATA_AHCI_CMD_WRITE 0x0040 +#define ATA_AHCI_CMD_PREFETCH 0x0080 +#define ATA_AHCI_CMD_RESET 0x0100 +#define ATA_AHCI_CMD_BIST 0x0200 +#define ATA_AHCI_CMD_CLR_BUSY 0x0400 + u_int16_t prd_length; /* PRD entries */ u_int32_t bytecount; u_int64_t cmd_table_phys; /* 128byte aligned */ @@ -291,7 +301,7 @@ struct ata_ahci_cmd_list { #define ATA_PC98_CTLADDR_RID 8 #define ATA_PC98_BANKADDR_RID 9 #define ATA_IRQ_RID 0 -#define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1) +#define ATA_DEV(unit) ((unit == ATA_ATA_SLAVE) ? 0x10 : 0) #define ATA_CFA_MAGIC1 0x844A #define ATA_CFA_MAGIC2 0x848A #define ATA_CFA_MAGIC3 0x8400 @@ -343,6 +353,7 @@ struct ata_request { u_int32_t bytecount; /* bytes to transfer */ u_int32_t transfersize; /* bytes pr transfer */ caddr_t data; /* pointer to data buf */ + u_int32_t tag; /* HW tag of this request */ int flags; #define ATA_R_CONTROL 0x00000001 #define ATA_R_READ 0x00000002 @@ -364,7 +375,16 @@ struct ata_request { u_int8_t status; /* ATA status */ u_int8_t error; /* ATA error */ - u_int8_t dmastat; /* DMA status */ + struct { + u_int8_t status; /* DMA status */ + 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 */ + u_int32_t cur_iosize; /* DMA data current IO size */ + } dma; u_int32_t donecount; /* bytes transferred */ int result; /* result error code */ void (*callback)(struct ata_request *request); @@ -398,6 +418,7 @@ struct ata_device { device_t dev; /* device handle */ int unit; /* physical unit */ #define ATA_MASTER 0x00 +#define ATA_PM 0x0f #define ATA_SLAVE 0x10 struct ata_params param; /* ata param structure */ @@ -429,40 +450,33 @@ struct ata_dmasetprd_args { /* structure holding DMA related information */ struct ata_dma { 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 SG list alignment */ u_int32_t boundary; /* DMA SG list boundary */ u_int32_t segsize; /* DMA SG list segment size */ u_int32_t max_iosize; /* DMA data max IO size */ - u_int32_t cur_iosize; /* DMA data current IO size */ u_int64_t max_address; /* highest DMA'able address */ 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 */ +#define ATA_DMA_ACTIVE 0x01 /* DMA transfer in progress */ void (*alloc)(device_t dev); void (*free)(device_t dev); void (*setprd)(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); - int (*load)(device_t dev, caddr_t data, int32_t count, int dir, void *addr, int *nsegs); - int (*unload)(device_t dev); - int (*start)(device_t dev); - int (*stop)(device_t dev); + int (*load)(struct ata_request *request, void *addr, int *nsegs); + int (*unload)(struct ata_request *request); + int (*start)(struct ata_request *request); + int (*stop)(struct ata_request *request); void (*reset)(device_t dev); }; /* structure holding lowlevel functions */ struct ata_lowlevel { + u_int32_t (*softreset)(device_t dev, int pmport); + int (*pm_read)(device_t dev, int port, int reg, u_int32_t *result); + int (*pm_write)(device_t dev, int port, int reg, u_int32_t value); int (*status)(device_t dev); int (*begin_transaction)(struct ata_request *request); int (*end_transaction)(struct ata_request *request); @@ -485,7 +499,7 @@ struct ata_channel { 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 */ + struct ata_dma dma; /* DMA data / functions */ int flags; /* channel flags */ #define ATA_NO_SLAVE 0x01 #define ATA_USE_16BIT 0x02 @@ -494,11 +508,11 @@ struct ata_channel { #define ATA_ALWAYS_DMASTAT 0x10 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 -#define ATA_PORTMULTIPLIER 0x10 +#define ATA_ATA_MASTER 0x00000001 +#define ATA_ATA_SLAVE 0x00000002 +#define ATA_PORTMULTIPLIER 0x00008000 +#define ATA_ATAPI_MASTER 0x00010000 +#define ATA_ATAPI_SLAVE 0x00020000 struct mtx state_mtx; /* state lock */ int state; /* ATA channel state */ @@ -524,6 +538,7 @@ extern int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data); extern struct intr_config_hook *ata_delayed_attach; extern devclass_t ata_devclass; extern int ata_wc; +extern int ata_setmax; /* public prototypes */ /* ata-all.c: */ @@ -535,10 +550,12 @@ int ata_suspend(device_t dev); int ata_resume(device_t dev); int ata_interrupt(void *data); int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data); +int ata_getparam(struct ata_device *atadev, int init); int ata_identify(device_t dev); void ata_default_registers(device_t dev); void ata_modify_if_48bit(struct ata_request *request); void ata_udelay(int interval); +char *ata_unit2str(struct ata_device *atadev); char *ata_mode2str(int mode); int ata_pmode(struct ata_params *ap); int ata_wmode(struct ata_params *ap); diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c index dcd43e7..9a66419 100644 --- a/sys/dev/ata/ata-card.c +++ b/sys/dev/ata/ata-card.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c index c978dc3..3ca86a3 100644 --- a/sys/dev/ata/ata-cbus.c +++ b/sys/dev/ata/ata-cbus.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2002 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 29a6117..d6ff0ac 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,6 +66,9 @@ static int ata_ahci_allocate(device_t dev); static int ata_ahci_status(device_t dev); static int ata_ahci_begin_transaction(struct ata_request *request); static int ata_ahci_end_transaction(struct ata_request *request); +static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result); +static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result); +static u_int32_t ata_ahci_softreset(device_t dev, int port); static void ata_ahci_reset(device_t dev); static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_ahci_dmainit(device_t dev); @@ -130,8 +133,8 @@ static void ata_nvidia_reset(device_t dev); static int ata_promise_chipinit(device_t dev); static int ata_promise_allocate(device_t dev); static int ata_promise_status(device_t dev); -static int ata_promise_dmastart(device_t dev); -static int ata_promise_dmastop(device_t dev); +static int ata_promise_dmastart(struct ata_request *request); +static int ata_promise_dmastop(struct ata_request *request); static void ata_promise_dmareset(device_t dev); static void ata_promise_dmainit(device_t dev); static void ata_promise_setmode(device_t dev, int mode); @@ -142,6 +145,9 @@ static void ata_promise_mio_intr(void *data); static int ata_promise_mio_status(device_t dev); static int ata_promise_mio_command(struct ata_request *request); static void ata_promise_mio_reset(device_t dev); +static int ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result); +static int ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t result); +static u_int32_t ata_promise_mio_softreset(device_t dev, int port); static void ata_promise_mio_dmainit(device_t dev); static void ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_promise_mio_setmode(device_t dev, int mode); @@ -167,6 +173,9 @@ static int ata_siiprb_allocate(device_t dev); static int ata_siiprb_status(device_t dev); static int ata_siiprb_begin_transaction(struct ata_request *request); static int ata_siiprb_end_transaction(struct ata_request *request); +static int ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result); +static int ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t result); +static u_int32_t ata_siiprb_softreset(device_t dev, int port); static void ata_siiprb_reset(device_t dev); static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_siiprb_dmainit(device_t dev); @@ -268,15 +277,15 @@ ata_sata_phy_check_events(device_t dev) if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) || ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) { if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); + device_printf(dev, "CONNECT requested\n"); tp->action = ATA_C_ATTACH; } else { if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); + device_printf(dev, "DISCONNECT requested\n"); tp->action = ATA_C_DETACH; } - tp->dev = ch->dev; + tp->dev = dev; TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); taskqueue_enqueue(taskqueue_thread, &tp->task); } @@ -407,14 +416,109 @@ ata_sata_setmode(device_t dev, int mode) } } +static void +ata_pm_identify(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + u_int32_t pm_chipid, pm_revision, pm_ports; + int port; + + /* get PM vendor & product data */ + if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) { + device_printf(dev, "error getting PM vendor data\n"); + return; + } + + /* get PM revision data */ + if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) { + device_printf(dev, "error getting PM revison data\n"); + return; + } + + /* get number of HW ports on the PM */ + if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) { + device_printf(dev, "error getting PM port info\n"); + return; + } + pm_ports &= 0x0000000f; + + /* chip specific quirks */ + switch (pm_chipid) { + case 0x37261095: + /* Some of these bogusly reports 6 ports */ + pm_ports = 5; + device_printf(dev, "SiI-3726-R%x Portmultiplier with %d ports\n", + pm_revision, pm_ports); + break; + + default: + device_printf(dev, "Portmultiplier (id=%08x rev=%x) with %d ports\n", + pm_chipid, pm_revision, pm_ports); + } + + /* reset all ports and register if anything connected */ + for (port=0; port < pm_ports; port++) { + u_int32_t signature, status; + int timeout; + + if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_RESET)) { + device_printf(dev, "p%d: writing ATA_SC_DET_RESET failed\n", port); + continue; + } + + ata_udelay(5000); + + if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_IDLE)) { + device_printf(dev, "p%d: writing ATA_SC_DET_idle failed\n", port); + continue; + } + + ata_udelay(5000); + + /* wait up to 1 second for "connect well" */ + for (timeout = 0; timeout < 100 ; timeout++) { + ch->hw.pm_read(dev, port, 0, &status); + if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 || + (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2) + break; + ata_udelay(10000); + } + if (timeout >= 100) { + if (bootverbose) + device_printf(dev, "p%d: connect status=%08x\n", port, status); + continue; + } + if (bootverbose) + device_printf(dev, "p%d: connect time %dms\n", port, timeout * 10); + + /* clear SERROR register */ + ch->hw.pm_write(dev, port, 1, 0xffffffff); + + signature = ch->hw.softreset(dev, port); + + if (bootverbose) + device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature); + + /* figure out whats there */ + switch (signature) { + case 0x00000101: + ch->devices |= (ATA_ATA_MASTER << port); + continue; + case 0xeb140101: + ch->devices |= (ATA_ATAPI_MASTER << port); + continue; + } + } +} + static int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis) { struct ata_device *atadev = device_get_softc(request->dev); if (request->flags & ATA_R_ATAPI) { - fis[0] = 0x27; /* host to device */ - fis[1] = 0x80; /* command FIS (note PM goes here) */ + fis[0] = 0x27; /* host to device */ + fis[1] = 0x80 | (atadev->unit & 0x0f); fis[2] = ATA_PACKET_CMD; if (request->flags & (ATA_R_READ | ATA_R_WRITE)) fis[3] = ATA_F_DMA; @@ -422,22 +526,22 @@ ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis) fis[5] = request->transfersize; fis[6] = request->transfersize >> 8; } - fis[7] = ATA_D_LBA | atadev->unit; + fis[7] = ATA_D_LBA; fis[15] = ATA_A_4BIT; return 20; } else { ata_modify_if_48bit(request); - fis[0] = 0x27; /* host to device */ - fis[1] = 0x80; /* command FIS (note PM goes here) */ + fis[0] = 0x27; /* host to device */ + fis[1] = 0x80 | (atadev->unit & 0x0f); fis[2] = request->u.ata.command; fis[3] = request->u.ata.feature; fis[4] = request->u.ata.lba; fis[5] = request->u.ata.lba >> 8; fis[6] = request->u.ata.lba >> 16; - fis[7] = ATA_D_LBA | atadev->unit; + fis[7] = ATA_D_LBA; if (!(atadev->flags & ATA_D_48BIT_ACTIVE)) - fis[7] |= (request->u.ata.lba >> 24 & 0x0f); + fis[7] |= (ATA_D_IBM | (request->u.ata.lba >> 24 & 0x0f)); fis[8] = request->u.ata.lba >> 24; fis[9] = request->u.ata.lba >> 32; fis[10] = request->u.ata.lba >> 40; @@ -534,10 +638,12 @@ ata_ahci_chipinit(device_t dev) /* announce we support the HW */ version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS); device_printf(dev, - "AHCI Version %x%x.%x%x controller with %d ports detected\n", + "AHCI Version %x%x.%x%x controller with %d ports PM %s\n", (version >> 24) & 0xff, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, - (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1); + (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1, + (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ? + "supported" : "not supported"); return 0; } @@ -563,13 +669,16 @@ ata_ahci_allocate(device_t dev) ch->hw.begin_transaction = ata_ahci_begin_transaction; ch->hw.end_transaction = ata_ahci_end_transaction; ch->hw.command = NULL; /* not used here */ + ch->hw.softreset = ata_ahci_softreset; + ch->hw.pm_read = ata_ahci_pm_read; + ch->hw.pm_write = ata_ahci_pm_write; /* setup work areas */ - work = ch->dma->work_bus + ATA_AHCI_CL_OFFSET; + work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); - work = ch->dma->work_bus + ATA_AHCI_FB_OFFSET; + work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); @@ -581,6 +690,9 @@ ata_ahci_allocate(device_t dev) ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); + /* enable FIS based switching */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003); + /* start operations on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | @@ -595,7 +707,6 @@ ata_ahci_status(device_t dev) struct ata_channel *ch = device_get_softc(dev); u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); int offset = ch->unit << 7; - int tag = 0; if (action & (1 << ch->unit)) { u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); @@ -610,7 +721,8 @@ ata_ahci_status(device_t dev) ata_sata_phy_check_events(dev); /* do we have a potentially hanging engine to take care of? */ - if ((istatus & 0x78400050) && (cstatus & (1 << tag))) { + /* XXX SOS what todo on NCQ */ + if ((istatus & 0x78400050) && (cstatus & 1)) { u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); int timeout = 0; @@ -622,7 +734,7 @@ ata_ahci_status(device_t dev) /* XXX SOS this is not entirely wrong */ do { DELAY(1000); - if (timeout++ > 500) { + if (timeout++ > 1000) { device_printf(dev, "stopping AHCI engine failed\n"); break; } @@ -636,7 +748,8 @@ ata_ahci_status(device_t dev) return 1; } else - return (!(cstatus & (1 << tag))); + /* XXX SOS what todo on NCQ */ + return (!(cstatus & 1)); } return 0; } @@ -646,16 +759,18 @@ static int ata_ahci_begin_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); + struct ata_device *atadev = device_get_softc(request->dev); struct ata_ahci_cmd_tab *ctp; struct ata_ahci_cmd_list *clp; int offset = ch->unit << 7; - int tag = 0, entries = 0; + int port = atadev->unit & 0x0f; + int entries = 0; int fis_size; /* get a piece of the workspace for this request */ ctp = (struct ata_ahci_cmd_tab *) - (ch->dma->work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * tag)); + (ch->dma.work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE*request->tag)); /* setup the FIS for this request */ if (!(fis_size = ata_ahci_setup_fis(ctp, request))) { @@ -666,9 +781,7 @@ ata_ahci_begin_transaction(struct ata_request *request) /* if request moves data setup and load SG list */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { - if (ch->dma->load(ch->dev, request->data, request->bytecount, - request->flags & ATA_R_READ, - ctp->prd_tab, &entries)) { + if (ch->dma.load(request, ctp->prd_tab, &entries)) { device_printf(request->dev, "setting up DMA failed\n"); request->result = EIO; return ATA_OP_FINISHED; @@ -677,18 +790,21 @@ ata_ahci_begin_transaction(struct ata_request *request) /* setup the command list entry */ clp = (struct ata_ahci_cmd_list *) - (ch->dma->work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE * tag)); + (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag)); clp->prd_length = entries; - clp->cmd_flags = (request->flags & ATA_R_WRITE ? (1<<6) : 0) | - (request->flags & ATA_R_ATAPI ? ((1<<5) | (1<<7)) : 0) | - (fis_size / sizeof(u_int32_t)); + clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) | + (request->flags & ATA_R_ATAPI ? + (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) | + (fis_size / sizeof(u_int32_t)) | + (port << 12); clp->bytecount = 0; - clp->cmd_table_phys = htole64(ch->dma->work_bus + ATA_AHCI_CT_OFFSET + - (ATA_AHCI_CT_SIZE * tag)); + clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET + + (ATA_AHCI_CT_SIZE * request->tag)); /* clear eventual ACTIVE bit */ - ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag)); + ATA_IDX_OUTL(ch, ATA_SACTIVE, + ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << request->tag)); /* set command type bit */ if (request->flags & ATA_R_ATAPI) @@ -700,8 +816,11 @@ ata_ahci_begin_transaction(struct ata_request *request) ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ~ATA_AHCI_P_CMD_ATAPI); + /* set PM port to address */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001); + /* issue command to controller */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << tag)); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << request->tag)); if (!(request->flags & ATA_R_ATAPI)) { /* device reset doesn't interrupt */ @@ -734,11 +853,10 @@ static int ata_ahci_end_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_ahci_cmd_list *clp; u_int32_t tf_data; int offset = ch->unit << 7; - int tag = 0; /* kill the timeout */ callout_stop(&request->callout); @@ -751,31 +869,140 @@ ata_ahci_end_transaction(struct ata_request *request) if (request->status & ATA_S_ERROR) request->error = tf_data >> 8; + /* on control commands read back registers to the request struct */ + if (request->flags & ATA_R_CONTROL) { + struct ata_device *atadev = device_get_softc(request->dev); + u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; + + request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8); + request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) | + ((u_int64_t)fis[6] << 16); + if (atadev->flags & ATA_D_48BIT_ACTIVE) + request->u.ata.lba |= ((u_int64_t)fis[8] << 24) | + ((u_int64_t)fis[9] << 32) | + ((u_int64_t)fis[10] << 40); + else + request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24); + } + /* record how much data we actually moved */ clp = (struct ata_ahci_cmd_list *) - (ch->dma->work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE * tag)); + (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag)); request->donecount = clp->bytecount; /* release SG list etc */ - ch->dma->unload(ch->dev); + ch->dma.unload(request); return ATA_OP_FINISHED; } -static void -ata_ahci_reset(device_t dev) +static int +ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - u_int32_t cmd, signature; + struct ata_ahci_cmd_list *clp = + (struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET); + struct ata_ahci_cmd_tab *ctp = + (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); + u_int32_t status = 0; int offset = ch->unit << 7; - int timeout; + int port = (ctp->cfis[1] & 0x0f); + int count; - if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { - device_printf(dev, "port not implemented\n"); - return; + clp->prd_length = 0; + clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12); + clp->bytecount = 0; + clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET); + + /* set PM port */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001); + + /* issue command to controller */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1); + + /* poll for command finished */ + for (count = 0; count < timeout; count++) { + DELAY(1000); + if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1)) + break; + } + + /* clear interrupts */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); + + if (bootverbose) + device_printf(dev, "ahci_issue_cmd time=%dms cnt=%dms status=%08x\n", + timeout, count, status); + if (timeout && (count >= timeout)) + return EIO; + + return 0; +} + +static int +ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result) +{ + struct ata_channel *ch = device_get_softc(dev); + struct ata_ahci_cmd_tab *ctp = + (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); + u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; + + bzero(ctp->cfis, 64); + ctp->cfis[0] = 0x27; /* host to device */ + ctp->cfis[1] = 0x8f; /* command FIS to PM port */ + ctp->cfis[2] = ATA_READ_PM; + ctp->cfis[3] = reg; + ctp->cfis[7] = port | ATA_D_LBA; + ctp->cfis[15] = ATA_A_4BIT; + + if (ata_ahci_issue_cmd(dev, 0, 10)) { + device_printf(dev, "error reading PM port\n"); + return EIO; + } + + *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24); + return 0; +} + +static int +ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + struct ata_ahci_cmd_tab *ctp = + (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); + int offset = ch->unit << 7; + + bzero(ctp->cfis, 64); + ctp->cfis[0] = 0x27; /* host to device */ + ctp->cfis[1] = 0x8f; /* command FIS to PM port */ + ctp->cfis[2] = ATA_WRITE_PM; + ctp->cfis[3] = reg; + ctp->cfis[7] = port | ATA_D_LBA; + ctp->cfis[12] = value & 0xff; + ctp->cfis[4] = (value >> 8) & 0xff;; + ctp->cfis[5] = (value >> 16) & 0xff;; + ctp->cfis[6] = (value >> 24) & 0xff;; + ctp->cfis[15] = ATA_A_4BIT; + + if (ata_ahci_issue_cmd(dev, 0, 100)) { + device_printf(dev, "error writing PM port\n"); + return ATA_E_ABORT; } - ch->devices = 0; + + return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff; +} + +static void +ata_ahci_restart(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + u_int32_t cmd; + int offset = ch->unit << 7; + int timeout; /* kill off all activity on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); @@ -786,7 +1013,7 @@ ata_ahci_reset(device_t dev) timeout = 0; do { DELAY(1000); - if (timeout++ > 500) { + if (timeout++ > 1000) { device_printf(dev, "stopping AHCI engine failed\n"); break; } @@ -801,7 +1028,7 @@ ata_ahci_reset(device_t dev) timeout = 0; do { DELAY(1000); - if (timeout++ > 500) { + if (timeout++ > 1000) { device_printf(dev, "executing CLO failed\n"); break; } @@ -809,45 +1036,119 @@ ata_ahci_reset(device_t dev) while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO); } - /* reset PHY and decide what is present */ - if (ata_sata_phy_reset(dev)) { + /* clear SATA error register */ + ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); + + /* clear any interrupts pending on this channel */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); + + /* start operations on this channel */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | + ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST) + | (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0)); +} + +static u_int32_t +ata_ahci_softreset(device_t dev, int port) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + struct ata_ahci_cmd_tab *ctp = + (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); + int offset = ch->unit << 7; + int timeout = 0; - /* clear any interrupts pending on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, - ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); + /* kick controller into sane state if needed */ + ata_ahci_restart(dev); - /* clear SATA error register */ - ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); + /* pull reset active */ + bzero(ctp->cfis, 64); + ctp->cfis[0] = 0x27; + ctp->cfis[1] = port & 0x0f; + //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; + ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET); - /* start operations on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | - ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)); + if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100)) + device_printf(dev, "setting SRST failed ??\n"); + //return -1; + + ata_udelay(5000); + + /* pull reset inactive -> device softreset */ + bzero(ctp->cfis, 64); + ctp->cfis[0] = 0x27; + ctp->cfis[1] = port & 0x0f; + //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; + ctp->cfis[15] = ATA_A_4BIT; + if (ata_ahci_issue_cmd(dev, 0, 0)) + return -1; + + ata_udelay(150000); + + timeout = 0; + do { + DELAY(1000); + if (timeout++ > 1000) { + device_printf(dev, "still BUSY after softreset\n"); + break; + } + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) & ATA_S_BUSY); + if (bootverbose) + device_printf(dev, "BUSY wait time=%dms\n", timeout); + + return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); +} + +static void +ata_ahci_reset(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + u_int32_t signature; + + if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { + device_printf(dev, "port not implemented\n"); + return; + } + + ata_ahci_restart(dev); - signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); + if (!ata_sata_phy_reset(dev)) { if (bootverbose) - device_printf(dev, "SIGNATURE: %08x\n", signature); - switch (signature) { - case 0x00000101: - ch->devices = ATA_ATA_MASTER; - break; - case 0x96690101: - ch->devices = ATA_PORTMULTIPLIER; - device_printf(ch->dev, "Portmultipliers not supported yet\n"); - ch->devices = 0; - break; - case 0xeb140101: - ch->devices = ATA_ATAPI_MASTER; - break; - default: /* SOS XXX */ - if (bootverbose) - device_printf(ch->dev, "No signature, asuming disk device\n"); - ch->devices = ATA_ATA_MASTER; - } + device_printf(dev, "phy reset found no device\n"); + ch->devices = 0; + return; + } + + /* only probe for PortMultiplier if HW has support */ + if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) + signature = ata_ahci_softreset(dev, ATA_PM); + else { + signature = ata_ahci_softreset(dev, 0); + } + if (bootverbose) + device_printf(dev, "SIGNATURE: %08x\n", signature); + + switch (signature) { + case 0x00000101: + ch->devices = ATA_ATA_MASTER; + break; + case 0x96690101: + ch->devices = ATA_PORTMULTIPLIER; + ata_pm_identify(dev); + break; + case 0xeb140101: + ch->devices = ATA_ATAPI_MASTER; + break; + default: /* SOS XXX */ + if (bootverbose) + device_printf(dev, "No signature, asuming disk device\n"); + ch->devices = ATA_ATA_MASTER; } if (bootverbose) - device_printf(dev, "ahci_reset devices=0x%b\n", ch->devices, - "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); + device_printf(dev, "ahci_reset devices=%08x\n", ch->devices); } static void @@ -863,7 +1164,9 @@ ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK); } } - KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n")); + + /* we only have space for 16 entries in a slot */ + KASSERT(nsegs <= 16, ("too many DMA segment entries\n")); args->nsegs = nsegs; } @@ -874,13 +1177,11 @@ ata_ahci_dmainit(device_t dev) struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); - if (ch->dma) { - /* note start and stop are not used here */ - ch->dma->setprd = ata_ahci_dmasetprd; - ch->dma->max_iosize = 8192 * DEV_BSIZE; - if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT) - ch->dma->max_address = BUS_SPACE_MAXADDR; - } + /* note start and stop are not used here */ + ch->dma.setprd = ata_ahci_dmasetprd; + ch->dma.max_iosize = 8192 * DEV_BSIZE; + if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT) + ch->dma.max_address = BUS_SPACE_MAXADDR; } static int @@ -956,9 +1257,9 @@ ata_acard_status(device_t dev) struct ata_channel *ch = device_get_softc(dev); if (ctlr->chip->cfg1 == ATPOLD && - ATA_LOCKING(ch->dev, ATA_LF_WHICH) != ch->unit) + ATA_LOCKING(dev, ATA_LF_WHICH) != ch->unit) return 0; - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { + if (ch->dma.flags & ATA_DMA_ACTIVE) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != @@ -985,7 +1286,7 @@ ata_acard_850_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; mode = ata_limit_mode(dev, mode, @@ -1021,7 +1322,7 @@ ata_acard_86X_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; @@ -1234,7 +1535,7 @@ ata_ali_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); @@ -1398,7 +1699,7 @@ ata_ati_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int offset = (devno ^ 0x01) << 3; int error; u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, @@ -1492,15 +1793,15 @@ ata_cyrix_setmode(device_t dev, int mode) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; u_int32_t piotiming[] = { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 }; u_int32_t dmatiming[] = { 0x00077771, 0x00012121, 0x00002020 }; u_int32_t udmatiming[] = { 0x00921250, 0x00911140, 0x00911030 }; int error; - ch->dma->alignment = 16; - ch->dma->max_iosize = 126 * DEV_BSIZE; + ch->dma.alignment = 16; + ch->dma.max_iosize = 126 * DEV_BSIZE; mode = ata_limit_mode(dev, mode, ATA_UDMA2); @@ -1681,7 +1982,7 @@ ata_highpoint_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; u_int32_t timings33[][4] = { /* HPT366 HPT370 HPT372 HPT374 mode */ @@ -1960,7 +2261,7 @@ ata_intel_new_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; u_int32_t reg40 = pci_read_config(gparent, 0x40, 4); u_int8_t reg44 = pci_read_config(gparent, 0x44, 1); u_int8_t reg48 = pci_read_config(gparent, 0x48, 1); @@ -2042,7 +2343,7 @@ ata_intel_sata_setmode(device_t dev, int mode) atadev->param.satacapabilities != 0xffff) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; /* on some drives we need to set the transfer mode */ ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, @@ -2116,11 +2417,13 @@ ata_intel_31244_allocate(device_t dev) static int ata_intel_31244_status(device_t dev) { + struct ata_channel *ch = device_get_softc(dev); + /* do we have any PHY events ? */ ata_sata_phy_check_events(dev); /* any drive action to take care of ? */ - return ata_pci_status(dev); + return ch->hw.status(dev); } static void @@ -2138,7 +2441,7 @@ ata_intel_31244_tf_write(struct ata_request *request) ((request->u.ata.lba >> 8) & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | ((request->u.ata.lba >> 16) & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit); + ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit)); } else { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); @@ -2159,7 +2462,7 @@ ata_intel_31244_tf_write(struct ata_request *request) (request->u.ata.lba / (sectors * heads))); ATA_IDX_OUTB(ch, ATA_CYL_MSB, (request->u.ata.lba / (sectors * heads)) >> 8); - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) | (((request->u.ata.lba% (sectors * heads)) / sectors) & 0xf)); } @@ -2168,7 +2471,7 @@ ata_intel_31244_tf_write(struct ata_request *request) ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTB(ch, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | atadev->unit | + ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } @@ -2227,7 +2530,7 @@ ata_ite_setmode(device_t dev, int mode) device_t gparent = GRANDPARENT(dev); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; /* correct the mode for what the HW supports */ @@ -2260,7 +2563,7 @@ ata_ite_setmode(device_t dev, int mode) /* set UDMA timing */ pci_write_config(gparent, - 0x56 + (ch->unit << 2) + ATA_DEV(atadev->unit), + 0x56 + (ch->unit << 2) + atadev->unit, udmatiming[mode & ATA_MODE_MASK], 1); } else { @@ -2570,11 +2873,11 @@ ata_marvell_edma_allocate(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - u_int64_t work = ch->dma->work_bus; + u_int64_t work = ch->dma.work_bus; int i; /* clear work area */ - bzero(ch->dma->work, 1024+256); + bzero(ch->dma.work, 1024+256); /* set legacy ATA resources */ for (i = ATA_DATA; i <= ATA_COMMAND; i++) { @@ -2681,13 +2984,13 @@ static int ata_marvell_edma_begin_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); u_int32_t req_in; u_int8_t *bytep; u_int16_t *wordp; u_int32_t *quadp; - int i, tag = 0x07; - int dummy, error, slot; + int i; + int error, slot; /* only DMA R/W goes through the EMDA machine */ if (request->u.ata.command != ATA_READ_DMA && @@ -2703,9 +3006,7 @@ ata_marvell_edma_begin_transaction(struct ata_request *request) ata_modify_if_48bit(request); /* check sanity, setup SG list and DMA engine */ - if ((error = ch->dma->load(ch->dev, request->data, request->bytecount, - request->flags & ATA_R_READ, ch->dma->sg, - &dummy))) { + if ((error = ch->dma.load(request, NULL, NULL))) { device_printf(request->dev, "setting up DMA failed\n"); request->result = error; return ATA_OP_FINISHED; @@ -2714,15 +3015,15 @@ ata_marvell_edma_begin_transaction(struct ata_request *request) /* get next free request queue slot */ req_in = ATA_INL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch)); slot = (((req_in & ~0xfffffc00) >> 5) + 0) & 0x1f; - bytep = (u_int8_t *)(ch->dma->work); + bytep = (u_int8_t *)(ch->dma.work); bytep += (slot << 5); wordp = (u_int16_t *)bytep; quadp = (u_int32_t *)bytep; /* fill in this request */ - quadp[0] = (long)ch->dma->sg_bus & 0xffffffff; - quadp[1] = (u_int64_t)ch->dma->sg_bus >> 32; - wordp[4] = (request->flags & ATA_R_READ ? 0x01 : 0x00) | (tag<<1); + quadp[0] = (long)request->dma.sg_bus & 0xffffffff; + quadp[1] = (u_int64_t)request->dma.sg_bus >> 32; + wordp[4] = (request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag<<1); i = 10; bytep[i++] = (request->u.ata.count >> 8) & 0xff; @@ -2773,7 +3074,7 @@ static int ata_marvell_edma_end_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); int offset = (ch->unit > 3 ? 0x30014 : 0x20014); u_int32_t icr = ATA_INL(ctlr->r_res1, offset); int res; @@ -2794,7 +3095,7 @@ ata_marvell_edma_end_transaction(struct ata_request *request) rsp_out &= 0xffffff00; rsp_out += (slot << 3); response = (struct ata_marvell_response *) - (ch->dma->work + 1024 + (slot << 3)); + (ch->dma.work + 1024 + (slot << 3)); /* record status for this request */ request->status = response->dev_status; @@ -2809,7 +3110,7 @@ ata_marvell_edma_end_transaction(struct ata_request *request) request->donecount = request->bytecount; /* unload SG list */ - ch->dma->unload(ch->dev); + ch->dma.unload(request); res = ATA_OP_FINISHED; } @@ -2880,17 +3181,15 @@ ata_marvell_edma_dmainit(device_t dev) struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); - if (ch->dma) { - /* note start and stop are not used here */ - ch->dma->setprd = ata_marvell_edma_dmasetprd; + /* note start and stop are not used here */ + ch->dma.setprd = ata_marvell_edma_dmasetprd; - /* if 64bit support present adjust max address used */ - if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004) - ch->dma->max_address = BUS_SPACE_MAXADDR; + /* if 64bit support present adjust max address used */ + if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004) + ch->dma.max_address = BUS_SPACE_MAXADDR; - /* chip does not reliably do 64K DMA transfers */ - ch->dma->max_iosize = 126 * DEV_BSIZE; - } + /* chip does not reliably do 64K DMA transfers */ + ch->dma.max_iosize = 126 * DEV_BSIZE; } @@ -2929,7 +3228,7 @@ ata_national_setmode(device_t dev, int mode) device_t gparent = GRANDPARENT(dev); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; u_int32_t piotiming[] = { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010, 0x00803020, 0x20102010, 0x00100010, @@ -2938,8 +3237,8 @@ ata_national_setmode(device_t dev, int mode) u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 }; int error; - ch->dma->alignment = 16; - ch->dma->max_iosize = 126 * DEV_BSIZE; + ch->dma.alignment = 16; + ch->dma.max_iosize = 126 * DEV_BSIZE; mode = ata_limit_mode(dev, mode, ATA_UDMA2); @@ -3405,7 +3704,7 @@ sataii: /* clear SATA status and unmask interrupts */ ATA_OUTL(ctlr->r_res2, stat_reg, 0x000000ff); - /* enable "long burst lenght" on gen2 chips */ + /* enable "long burst length" on gen2 chips */ if ((ctlr->chip->cfg2 == PRSATA2) || (ctlr->chip->cfg2 == PRCMBO2)) ATA_OUTL(ctlr->r_res2, 0x44, ATA_INL(ctlr->r_res2, 0x44) | 0x2000); @@ -3444,41 +3743,41 @@ ata_promise_status(device_t dev) struct ata_channel *ch = device_get_softc(dev); if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) { - return ata_pci_status(dev); + return ch->hw.status(dev); } return 0; } static int -ata_promise_dmastart(device_t dev) +ata_promise_dmastart(struct ata_request *request) { - struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_device *atadev = device_get_softc(dev); + struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); + struct ata_device *atadev = device_get_softc(request->dev); if (atadev->flags & ATA_D_48BIT_ACTIVE) { ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | (ch->unit ? 0x08 : 0x02)); ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20, - ((ch->dma->flags & ATA_DMA_READ) ? 0x05000000 : 0x06000000) | - (ch->dma->cur_iosize >> 1)); + ((request->flags & ATA_R_READ) ? 0x05000000 : 0x06000000) | + (request->dma.cur_iosize >> 1)); } 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->sg_bus); + ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, request->dma.sg_bus); ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, - ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | + ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP); - ch->flags |= ATA_DMA_ACTIVE; + ch->dma.flags |= ATA_DMA_ACTIVE; return 0; } static int -ata_promise_dmastop(device_t dev) +ata_promise_dmastop(struct ata_request *request) { - struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_device *atadev = device_get_softc(dev); + struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); + struct ata_device *atadev = device_get_softc(request->dev); int error; if (atadev->flags & ATA_D_48BIT_ACTIVE) { @@ -3490,7 +3789,7 @@ ata_promise_dmastop(device_t dev) ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); - ch->flags &= ~ATA_DMA_ACTIVE; + ch->dma.flags &= ~ATA_DMA_ACTIVE; return error; } @@ -3511,11 +3810,9 @@ ata_promise_dmainit(device_t dev) struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); - if (ch->dma) { - ch->dma->start = ata_promise_dmastart; - ch->dma->stop = ata_promise_dmastop; - ch->dma->reset = ata_promise_dmareset; - } + ch->dma.start = ata_promise_dmastart; + ch->dma.stop = ata_promise_dmastop; + ch->dma.reset = ata_promise_dmareset; } static void @@ -3525,7 +3822,7 @@ ata_promise_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; u_int32_t timings[][2] = { /* PROLD PRNEW mode */ @@ -3613,7 +3910,7 @@ ata_promise_tx2_status(device_t dev) ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b); if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) { - return ata_pci_status(dev); + return ch->hw.status(dev); } return 0; } @@ -3653,6 +3950,9 @@ ata_promise_mio_allocate(device_t dev) else { ch->hw.command = ata_promise_mio_command; ch->hw.status = ata_promise_mio_status; + ch->hw.softreset = ata_promise_mio_softreset; + ch->hw.pm_read = ata_promise_mio_pm_read; + ch->hw.pm_write = ata_promise_mio_pm_write; } return 0; } @@ -3734,9 +4034,9 @@ ata_promise_mio_status(device_t dev) M_ATA, M_NOWAIT | M_ZERO))) { if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); + device_printf(dev, "DISCONNECT requested\n"); tp->action = ATA_C_DETACH; - tp->dev = ch->dev; + tp->dev = dev; TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); taskqueue_enqueue(taskqueue_thread, &tp->task); } @@ -3748,9 +4048,9 @@ ata_promise_mio_status(device_t dev) M_ATA, M_NOWAIT | M_ZERO))) { if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); + device_printf(dev, "CONNECT requested\n"); tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; + tp->dev = dev; TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); taskqueue_enqueue(taskqueue_thread, &tp->task); } @@ -3763,11 +4063,16 @@ static int ata_promise_mio_command(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); - u_int32_t *wordp = (u_int32_t *)ch->dma->work; + struct ata_channel *ch = device_get_softc(request->parent); + struct ata_device *atadev = device_get_softc(request->dev); + + u_int32_t *wordp = (u_int32_t *)ch->dma.work; ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001); + /* set portmultiplier port */ + ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), atadev->unit & 0x0f); + /* XXX SOS add ATAPI commands support later */ switch (request->u.ata.command) { default: @@ -3783,11 +4088,11 @@ ata_promise_mio_command(struct ata_request *request) wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24)); break; } - wordp[1] = htole32(ch->dma->sg_bus); + wordp[1] = htole32(request->dma.sg_bus); wordp[2] = 0; ata_promise_apkt((u_int8_t*)wordp, request); - ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma->work_bus); + ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma.work_bus); return 0; } @@ -3856,7 +4161,7 @@ ata_promise_mio_reset(device_t dev) if ((ctlr->chip->cfg2 == PRSATA2) || ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) { /* set portmultiplier port */ - ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); + //ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); /* mask plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit)); @@ -3877,13 +4182,39 @@ ata_promise_mio_reset(device_t dev) (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) & ~0x00000003) | 0x00000001); - if (ata_sata_phy_reset(dev)) - ata_generic_reset(dev); + if (ata_sata_phy_reset(dev)) { + u_int32_t signature = ch->hw.softreset(dev, ATA_PM); + + if (1 | bootverbose) + device_printf(dev, "SIGNATURE: %08x\n", signature); + + switch (signature) { + case 0x00000101: + ch->devices = ATA_ATA_MASTER; + break; + case 0x96690101: + ch->devices = ATA_PORTMULTIPLIER; + ata_pm_identify(dev); + break; + case 0xeb140101: + ch->devices = ATA_ATAPI_MASTER; + break; + default: /* SOS XXX */ + if (bootverbose) + device_printf(dev, + "No signature, asuming disk device\n"); + ch->devices = ATA_ATA_MASTER; + } + if (bootverbose) + device_printf(dev, "promise_mio_reset devices=%08x\n", + ch->devices); + + } /* reset and enable plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit)); - /* set portmultiplier port */ + ///* set portmultiplier port */ ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00); } else @@ -3893,15 +4224,127 @@ ata_promise_mio_reset(device_t dev) } } +static int +ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int timeout = 0; + + /* set portmultiplier port */ + ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); + + ATA_IDX_OUTB(ch, ATA_FEATURE, reg); + ATA_IDX_OUTB(ch, ATA_DRIVE, port); + + ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_READ_PM); + + while (timeout < 1000000) { + u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS); + if (!(status & ATA_S_BUSY)) + break; + timeout += 1000; + DELAY(1000); + } + if (timeout >= 1000000) + return ATA_E_ABORT; + + *result = ATA_IDX_INB(ch, ATA_COUNT) | + (ATA_IDX_INB(ch, ATA_SECTOR) << 8) | + (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) | + (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24); + return 0; +} + +static int +ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int timeout = 0; + + /* set portmultiplier port */ + ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); + + ATA_IDX_OUTB(ch, ATA_FEATURE, reg); + ATA_IDX_OUTB(ch, ATA_DRIVE, port); + ATA_IDX_OUTB(ch, ATA_COUNT, value & 0xff); + ATA_IDX_OUTB(ch, ATA_SECTOR, (value >> 8) & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_LSB, (value >> 16) & 0xff); + ATA_IDX_OUTB(ch, ATA_CYL_MSB, (value >> 24) & 0xff); + + ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_WRITE_PM); + + while (timeout < 1000000) { + u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS); + if (!(status & ATA_S_BUSY)) + break; + timeout += 1000; + DELAY(1000); + } + if (timeout >= 1000000) + return ATA_E_ABORT; + + return ATA_IDX_INB(ch, ATA_ERROR); +} + +/* must be called with ATA channel locked and state_mtx held */ +static u_int32_t +ata_promise_mio_softreset(device_t dev, int port) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + int timeout; + + /* set portmultiplier port */ + ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), port & 0x0f); + + /* softreset device on this channel */ + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER); + DELAY(10); + ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET); + ata_udelay(10000); + ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS); + ata_udelay(150000); + ATA_IDX_INB(ch, ATA_ERROR); + + /* wait for BUSY to go inactive */ + for (timeout = 0; timeout < 100; timeout++) { + u_int8_t err, stat; + + err = ATA_IDX_INB(ch, ATA_ERROR); + stat = ATA_IDX_INB(ch, ATA_STATUS); + + //if (stat == err && timeout > (stat & ATA_S_BUSY ? 100 : 10)) + //break; + + if (!(stat & ATA_S_BUSY)) { + //if ((err & 0x7f) == ATA_E_ILI) { + return ATA_IDX_INB(ch, ATA_COUNT) | + (ATA_IDX_INB(ch, ATA_SECTOR) << 8) | + (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) | + (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24); + //} + //else if (stat & 0x0f) { + //stat |= ATA_S_BUSY; + //} + } + + if (!(stat & ATA_S_BUSY) || (stat == 0xff && timeout > 10)) + break; + ata_udelay(100000); + } + return -1; +} + static void ata_promise_mio_dmainit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); - /* note start and stop are not used here */ ata_dmainit(dev); - if (ch->dma) - ch->dma->setprd = ata_promise_mio_setprd; + /* note start and stop are not used here */ + ch->dma.setprd = ata_promise_mio_setprd; } @@ -3987,8 +4430,8 @@ ata_promise_sx4_command(struct ata_request *request) { device_t gparent = GRANDPARENT(request->dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); - struct ata_dma_prdentry *prd = ch->dma->sg; + struct ata_channel *ch = device_get_softc(request->parent); + struct ata_dma_prdentry *prd = request->dma.sg; caddr_t window = rman_get_virtual(ctlr->r_res1); u_int32_t *wordp; int i, idx, length = 0; @@ -4095,7 +4538,7 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) int i = 12; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE; - bytep[i++] = ATA_D_IBM | ATA_D_LBA | atadev->unit; + bytep[i++] = ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit); bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL; bytep[i++] = ATA_A_4BIT; @@ -4116,7 +4559,7 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) bytep[i++] = request->u.ata.lba >> 40; bytep[i++] = request->u.ata.lba >> 16; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE; - bytep[i++] = ATA_D_LBA | atadev->unit; + bytep[i++] = ATA_D_LBA | ATA_DEV(atadev->unit); } else { bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_FEATURE; @@ -4131,7 +4574,8 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) bytep[i++] = request->u.ata.lba >> 16; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE; bytep[i++] = (atadev->flags & ATA_D_USE_CHS ? 0 : ATA_D_LBA) | - ATA_D_IBM | atadev->unit | ((request->u.ata.lba >> 24)&0xf); + ATA_D_IBM | ATA_DEV(atadev->unit) | + ((request->u.ata.lba >> 24)&0xf); } bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_END | ATA_COMMAND; bytep[i++] = request->u.ata.command; @@ -4291,8 +4735,7 @@ ata_serverworks_allocate(device_t dev) ch->hw.tf_write = ata_serverworks_tf_write; /* chip does not reliably do 64K DMA transfers */ - if (ch->dma) - ch->dma->max_iosize = 126 * DEV_BSIZE; + ch->dma.max_iosize = 126 * DEV_BSIZE; return 0; } @@ -4300,7 +4743,7 @@ ata_serverworks_allocate(device_t dev) static void ata_serverworks_tf_read(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); if (atadev->flags & ATA_D_48BIT_ACTIVE) { @@ -4329,7 +4772,7 @@ ata_serverworks_tf_read(struct ata_request *request) static void ata_serverworks_tf_write(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); if (atadev->flags & ATA_D_48BIT_ACTIVE) { @@ -4341,7 +4784,7 @@ ata_serverworks_tf_write(struct ata_request *request) ((request->u.ata.lba >> 8) & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | ((request->u.ata.lba >> 16) & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit); + ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit)); } else { ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature); @@ -4362,7 +4805,7 @@ ata_serverworks_tf_write(struct ata_request *request) (request->u.ata.lba / (sectors * heads))); ATA_IDX_OUTW(ch, ATA_CYL_MSB, (request->u.ata.lba / (sectors * heads)) >> 8); - ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | + ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) | (((request->u.ata.lba% (sectors * heads)) / sectors) & 0xf)); } @@ -4371,7 +4814,7 @@ ata_serverworks_tf_write(struct ata_request *request) ATA_IDX_OUTW(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTW(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTW(ch, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | atadev->unit | + ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } @@ -4384,7 +4827,7 @@ ata_serverworks_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int offset = (devno ^ 0x01) << 3; int error; u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, @@ -4585,11 +5028,11 @@ ata_cmd_status(device_t dev) struct ata_channel *ch = device_get_softc(dev); u_int8_t reg71; - if (((reg71 = pci_read_config(device_get_parent(ch->dev), 0x71, 1)) & + if (((reg71 = pci_read_config(device_get_parent(dev), 0x71, 1)) & (ch->unit ? 0x08 : 0x04))) { - pci_write_config(device_get_parent(ch->dev), 0x71, + pci_write_config(device_get_parent(dev), 0x71, reg71 & ~(ch->unit ? 0x04 : 0x08), 1); - return ata_pci_status(dev); + return ch->hw.status(dev); } return 0; } @@ -4601,7 +5044,7 @@ ata_cmd_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); @@ -4626,7 +5069,7 @@ ata_cmd_setmode(device_t dev, int mode) u_int8_t umode = pci_read_config(gparent, ureg, 1); umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca); - umode |= udmatimings[mode & ATA_MODE_MASK][ATA_DEV(atadev->unit)]; + umode |= udmatimings[mode & ATA_MODE_MASK][atadev->unit]; pci_write_config(gparent, ureg, umode, 1); } else if (mode >= ATA_WDMA0) { @@ -4686,10 +5129,10 @@ ata_sii_allocate(device_t dev) ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); } - if ((ctlr->chip->cfg2 & SIIBUG) && ch->dma) { + if (ctlr->chip->cfg2 & SIIBUG) { /* work around errata in early chips */ - ch->dma->boundary = 8192; - ch->dma->segsize = 15 * DEV_BSIZE; + ch->dma.boundary = 8192; + ch->dma.segsize = 15 * DEV_BSIZE; } ata_pci_hw(dev); @@ -4711,7 +5154,7 @@ ata_sii_status(device_t dev) ata_sata_phy_check_events(dev); if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800) - return ata_pci_status(dev); + return ch->hw.status(dev); else return 0; } @@ -4730,9 +5173,9 @@ ata_sii_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int rego = (ch->unit << 4) + (ATA_DEV(atadev->unit) << 1); + int rego = (ch->unit << 4) + (atadev->unit << 1); int mreg = ch->unit ? 0x84 : 0x80; - int mask = 0x03 << (ATA_DEV(atadev->unit) << 2); + int mask = 0x03 << (atadev->unit << 2); int mval = pci_read_config(gparent, mreg, 1) & ~mask; int error; @@ -4762,7 +5205,7 @@ ata_sii_setmode(device_t dev, int mode) u_int8_t ureg = 0xac + rego; pci_write_config(gparent, mreg, - mval | (0x03 << (ATA_DEV(atadev->unit) << 2)), 1); + mval | (0x03 << (atadev->unit << 2)), 1); pci_write_config(gparent, ureg, (pci_read_config(gparent, ureg, 1) & ~0x3f) | udmatimings[mode & ATA_MODE_MASK], 1); @@ -4773,7 +5216,7 @@ ata_sii_setmode(device_t dev, int mode) u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 }; pci_write_config(gparent, mreg, - mval | (0x02 << (ATA_DEV(atadev->unit) << 2)), 1); + mval | (0x02 << (atadev->unit << 2)), 1); pci_write_config(gparent, dreg, dmatimings[mode & ATA_MODE_MASK], 2); } @@ -4782,7 +5225,7 @@ ata_sii_setmode(device_t dev, int mode) u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; pci_write_config(gparent, mreg, - mval | (0x01 << (ATA_DEV(atadev->unit) << 2)), 1); + mval | (0x01 << (atadev->unit << 2)), 1); pci_write_config(gparent, preg, piotimings[mode & ATA_MODE_MASK], 2); } atadev->mode = mode; @@ -4832,10 +5275,14 @@ ata_siiprb_allocate(device_t dev) ch->r_io[ATA_SACTIVE].res = ctlr->r_res2; ch->r_io[ATA_SACTIVE].offset = 0x1f0c + offset; + ch->hw.status = ata_siiprb_status; ch->hw.begin_transaction = ata_siiprb_begin_transaction; ch->hw.end_transaction = ata_siiprb_end_transaction; - ch->hw.status = ata_siiprb_status; ch->hw.command = NULL; /* not used here */ + ch->hw.softreset = ata_siiprb_softreset; + ch->hw.pm_read = ata_siiprb_pm_read; + ch->hw.pm_write = ata_siiprb_pm_write; + return 0; } @@ -4866,12 +5313,11 @@ static int ata_siiprb_begin_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_siiprb_command *prb; struct ata_siiprb_dma_prdentry *prd; int offset = ch->unit * 0x2000; u_int64_t prb_bus; - int tag = 0, dummy; /* SOS XXX */ if (request->u.ata.command == ATA_DEVICE_RESET) { @@ -4879,12 +5325,9 @@ ata_siiprb_begin_transaction(struct ata_request *request) return ATA_OP_FINISHED; } - /* check for 48 bit access and convert if needed */ - ata_modify_if_48bit(request); - /* get a piece of the workspace for this request */ prb = (struct ata_siiprb_command *) - (ch->dma->work + (sizeof(struct ata_siiprb_command) * tag)); + (ch->dma.work + (sizeof(struct ata_siiprb_command) * request->tag)); /* set basic prd options ata/atapi etc etc */ bzero(prb, sizeof(struct ata_siiprb_command)); @@ -4916,8 +5359,7 @@ ata_siiprb_begin_transaction(struct ata_request *request) /* if request moves data setup and load SG list */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { - if (ch->dma->load(ch->dev, request->data, request->bytecount, - request->flags & ATA_R_READ, prd, &dummy)) { + if (ch->dma.load(request, prd, NULL)) { device_printf(request->dev, "setting up DMA failed\n"); request->result = EIO; return ATA_OP_FINISHED; @@ -4925,11 +5367,12 @@ ata_siiprb_begin_transaction(struct ata_request *request) } /* activate the prb */ - prb_bus = ch->dma->work_bus + (sizeof(struct ata_siiprb_command) * tag); + prb_bus = ch->dma.work_bus + + (sizeof(struct ata_siiprb_command) * request->tag); ATA_OUTL(ctlr->r_res2, - 0x1c00 + offset + (tag * sizeof(u_int64_t)), prb_bus); + 0x1c00 + offset + (request->tag * sizeof(u_int64_t)), prb_bus); ATA_OUTL(ctlr->r_res2, - 0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32); + 0x1c04 + offset + (request->tag * sizeof(u_int64_t)), prb_bus>>32); /* start the timeout */ callout_reset(&request->callout, request->timeout * hz, @@ -4941,16 +5384,16 @@ static int ata_siiprb_end_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_siiprb_command *prb; int offset = ch->unit * 0x2000; - int error, timeout, tag = 0; + int error, timeout; /* kill the timeout */ callout_stop(&request->callout); prb = (struct ata_siiprb_command *) - ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset); + ((u_int8_t *)rman_get_virtual(ctlr->r_res2)+(request->tag << 7)+offset); /* any controller errors flagged ? */ if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) { @@ -4984,6 +5427,21 @@ ata_siiprb_end_transaction(struct ata_request *request) } } + /* on control commands read back registers to the request struct */ + if (request->flags & ATA_R_CONTROL) { + struct ata_device *atadev = device_get_softc(request->dev); + + request->u.ata.count = prb->fis[12] | ((u_int16_t)prb->fis[13] << 8); + request->u.ata.lba = prb->fis[4] | ((u_int64_t)prb->fis[5] << 8) | + ((u_int64_t)prb->fis[6] << 16); + if (atadev->flags & ATA_D_48BIT_ACTIVE) + request->u.ata.lba |= ((u_int64_t)prb->fis[8] << 24) | + ((u_int64_t)prb->fis[9] << 32) | + ((u_int64_t)prb->fis[10] << 40); + else + request->u.ata.lba |= ((u_int64_t)(prb->fis[7] & 0x0f) << 24); + } + /* update progress */ if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) { if (request->flags & ATA_R_READ) @@ -4993,21 +5451,126 @@ ata_siiprb_end_transaction(struct ata_request *request) } /* release SG list etc */ - ch->dma->unload(ch->dev); + ch->dma.unload(request); return ATA_OP_FINISHED; } +static int +ata_siiprb_issue_cmd(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + u_int64_t prb_bus = ch->dma.work_bus; + u_int32_t status; + int offset = ch->unit * 0x2000; + int timeout; + + /* issue command to chip */ + ATA_OUTL(ctlr->r_res2, 0x1c00 + offset, prb_bus); + ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus >> 32); + + /* poll for command finished */ + for (timeout = 0; timeout < 10000; timeout++) { + DELAY(1000); + if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000) + break; + } + ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x00010000); + + if (timeout >= 1000) + return EIO; + + if (bootverbose) + device_printf(dev, "siiprb_issue_cmd time=%dms status=%08x\n", + timeout, status); + return 0; +} + +static int +ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; + int offset = ch->unit * 0x2000; + + bzero(prb, sizeof(struct ata_siiprb_command)); + prb->fis[0] = 0x27; /* host to device */ + prb->fis[1] = 0x8f; /* command FIS to PM port */ + prb->fis[2] = ATA_READ_PM; + prb->fis[3] = reg; + prb->fis[7] = port; + if (ata_siiprb_issue_cmd(dev)) { + device_printf(dev, "error reading PM port\n"); + return EIO; + } + prb = (struct ata_siiprb_command *) + ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); + *result = prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24); + return 0; +} + +static int +ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; + int offset = ch->unit * 0x2000; + + bzero(prb, sizeof(struct ata_siiprb_command)); + prb->fis[0] = 0x27; /* host to device */ + prb->fis[1] = 0x8f; /* command FIS to PM port */ + prb->fis[2] = ATA_WRITE_PM; + prb->fis[3] = reg; + prb->fis[7] = port; + prb->fis[12] = value & 0xff; + prb->fis[4] = (value >> 8) & 0xff;; + prb->fis[5] = (value >> 16) & 0xff;; + prb->fis[6] = (value >> 24) & 0xff;; + if (ata_siiprb_issue_cmd(dev)) { + device_printf(dev, "error writing PM port\n"); + return ATA_E_ABORT; + } + prb = (struct ata_siiprb_command *) + ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); + return prb->fis[3]; +} + +static u_int32_t +ata_siiprb_softreset(device_t dev, int port) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; + int offset = ch->unit * 0x2000; + + /* setup the workspace for a soft reset command */ + bzero(prb, sizeof(struct ata_siiprb_command)); + prb->control = htole16(0x0080); + prb->fis[1] = port & 0x0f; + + /* issue soft reset */ + if (ata_siiprb_issue_cmd(dev)) + return -1; + + ata_udelay(150000); + + /* return possible signature */ + prb = (struct ata_siiprb_command *) + ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); + return prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24); +} + static void ata_siiprb_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit * 0x2000; - struct ata_siiprb_command *prb; - u_int64_t prb_bus; u_int32_t status, signature; - int timeout, tag = 0; + int timeout; /* reset channel HW */ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000001); @@ -5024,62 +5587,33 @@ ata_siiprb_reset(device_t dev) if (bootverbose) { if (timeout >= 1000) - device_printf(ch->dev, "channel HW reset timeout\n"); + device_printf(dev, "channel HW reset timeout\n"); else - device_printf(ch->dev, "channel HW reset time=%dms\n", timeout); + device_printf(dev, "channel HW reset time=%dms\n", timeout); } /* reset phy */ if (!ata_sata_phy_reset(dev)) { if (bootverbose) - device_printf(ch->dev, "phy reset found no device\n"); + device_printf(dev, "phy reset found no device\n"); ch->devices = 0; goto finish; } - /* get a piece of the workspace for a soft reset request */ - prb = (struct ata_siiprb_command *) - (ch->dma->work + (sizeof(struct ata_siiprb_command) * tag)); - bzero(prb, sizeof(struct ata_siiprb_command)); - prb->control = htole16(0x0080); - - /* activate the soft reset prb */ - prb_bus = ch->dma->work_bus + (sizeof(struct ata_siiprb_command) * tag); - ATA_OUTL(ctlr->r_res2, - 0x1c00 + offset + (tag * sizeof(u_int64_t)), prb_bus); - ATA_OUTL(ctlr->r_res2, - 0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32); - - /* poll for command finished */ - for (timeout = 0; timeout < 10000; timeout++) { - DELAY(1000); - if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000) - break; - } - if (timeout >= 1000) { - device_printf(ch->dev, "reset timeout - no device found\n"); - ch->devices = 0; - goto finish; - } + /* issue soft reset */ + signature = ata_siiprb_softreset(dev, ATA_PM); if (bootverbose) - device_printf(ch->dev, "soft reset exec time=%dms status=%08x\n", - timeout, status); + device_printf(dev, "SIGNATURE=%08x\n", signature); - /* find out whats there */ - prb = (struct ata_siiprb_command *) - ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset); - signature = - prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24); - if (bootverbose) - device_printf(ch->dev, "SIGNATURE=%08x\n", signature); + /* figure out whats there */ switch (signature) { case 0x00000101: ch->devices = ATA_ATA_MASTER; break; case 0x96690101: ch->devices = ATA_PORTMULTIPLIER; - device_printf(ch->dev, "Portmultipliers not supported yet\n"); - ch->devices = 0; + ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x2000); /* enable PM support */ + ata_pm_identify(dev); break; case 0xeb140101: ch->devices = ATA_ATAPI_MASTER; @@ -5088,8 +5622,7 @@ ata_siiprb_reset(device_t dev) ch->devices = 0; } if (bootverbose) - device_printf(dev, "siiprb_reset devices=0x%b\n", ch->devices, - "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); + device_printf(dev, "siiprb_reset devices=%08x\n", ch->devices); finish: /* clear interrupt(s) */ @@ -5130,11 +5663,9 @@ ata_siiprb_dmainit(device_t dev) struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); - if (ch->dma) { - /* note start and stop are not used here */ - ch->dma->setprd = ata_siiprb_dmasetprd; - ch->dma->max_address = BUS_SPACE_MAXADDR; - } + /* note start and stop are not used here */ + ch->dma.setprd = ata_siiprb_dmasetprd; + ch->dma.max_address = BUS_SPACE_MAXADDR; } @@ -5305,7 +5836,7 @@ ata_sis_setmode(device_t dev, int mode) struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int error; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); @@ -5630,7 +6161,7 @@ ata_via_family_setmode(device_t dev, int mode) { 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* VIA ATA100 */ { 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 }, /* VIA ATA133 */ { 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 }}; /* AMD/nVIDIA */ - int devno = (ch->unit << 1) + ATA_DEV(atadev->unit); + int devno = (ch->unit << 1) + atadev->unit; int reg = 0x53 - devno; int error; @@ -5784,7 +6315,7 @@ ata_serialize(device_t dev, int flags) if ((ch = ctlr->interrupt[serial->restart_ch].argument)) { serial->restart_ch = -1; mtx_unlock(&serial->locked_mtx); - ata_start(ch->dev); + ata_start(dev); return -1; } } diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 1ed4c20..a4d7959 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include <sys/conf.h> #include <sys/disk.h> #include <sys/cons.h> -#include <sys/sysctl.h> #include <sys/sema.h> #include <sys/taskqueue.h> #include <vm/uma.h> @@ -54,10 +53,12 @@ __FBSDID("$FreeBSD$"); #include <ata_if.h> /* prototypes */ -static void ad_init(device_t); -static void ad_done(struct ata_request *); +static void ad_init(device_t dev); +static void ad_get_geometry(device_t dev); +static void ad_set_geometry(device_t dev); +static void ad_done(struct ata_request *request); static void ad_describe(device_t dev); -static int ad_version(u_int16_t); +static int ad_version(u_int16_t version); static disk_strategy_t ad_strategy; static disk_ioctl_t ad_ioctl; static dumper_t ad_dump; @@ -93,8 +94,6 @@ ad_attach(device_t dev) struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); struct ad_softc *adp; - u_int32_t lbasize; - u_int64_t lbasize48; /* check that we have a virgin disk to attach */ if (device_get_ivars(dev)) @@ -106,37 +105,12 @@ ad_attach(device_t dev) } device_set_ivars(dev, adp); - if ((atadev->param.atavalid & ATA_FLAG_54_58) && - atadev->param.current_heads && atadev->param.current_sectors) { - adp->heads = atadev->param.current_heads; - adp->sectors = atadev->param.current_sectors; - adp->total_secs = (u_int32_t)atadev->param.current_size_1 | - ((u_int32_t)atadev->param.current_size_2 << 16); - } - else { - adp->heads = atadev->param.heads; - adp->sectors = atadev->param.sectors; - adp->total_secs = atadev->param.cylinders * adp->heads * adp->sectors; - } - lbasize = (u_int32_t)atadev->param.lba_size_1 | - ((u_int32_t)atadev->param.lba_size_2 << 16); - - /* does this device need oldstyle CHS addressing */ - if (!ad_version(atadev->param.version_major) || !lbasize) - atadev->flags |= ATA_D_USE_CHS; - - /* use the 28bit LBA size if valid or bigger than the CHS mapping */ - if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize) - adp->total_secs = lbasize; + /* get device geometry into internal structs */ + ad_get_geometry(dev); - /* use the 48bit LBA size if valid */ - lbasize48 = ((u_int64_t)atadev->param.lba_size48_1) | - ((u_int64_t)atadev->param.lba_size48_2 << 16) | - ((u_int64_t)atadev->param.lba_size48_3 << 32) | - ((u_int64_t)atadev->param.lba_size48_4 << 48); - if ((atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) && - lbasize48 > ATA_MAX_28BIT_LBA) - adp->total_secs = lbasize48; + /* set the max size if configured */ + if (ata_setmax) + ad_set_geometry(dev); /* init device parameters */ ad_init(dev); @@ -151,10 +125,7 @@ ad_attach(device_t dev) adp->disk->d_dump = ad_dump; adp->disk->d_name = "ad"; adp->disk->d_drv1 = dev; - if (ch->dma) - adp->disk->d_maxsize = ch->dma->max_iosize; - else - adp->disk->d_maxsize = DFLTPHYS; + adp->disk->d_maxsize = ch->dma.max_iosize; adp->disk->d_sectorsize = DEV_BSIZE; adp->disk->d_mediasize = DEV_BSIZE * (off_t)adp->total_secs; adp->disk->d_fwsectors = adp->sectors; @@ -249,7 +220,7 @@ ad_spindown(void *priv) struct ata_device *atadev = device_get_softc(dev); struct ata_request *request; - if(atadev->spindown == 0) + if (!atadev->spindown) return; device_printf(dev, "Idle, spin down\n"); atadev->spindown_state = 1; @@ -274,9 +245,9 @@ ad_strategy(struct bio *bp) struct ata_device *atadev = device_get_softc(dev); struct ata_request *request; - if (atadev->spindown != 0) + if (atadev->spindown) callout_reset(&atadev->spindown_timer, hz * atadev->spindown, - ad_spindown, dev); + ad_spindown, dev); if (!(request = ata_alloc_request())) { device_printf(dev, "FAILURE - out of memory in start\n"); @@ -292,7 +263,8 @@ ad_strategy(struct bio *bp) device_printf(dev, "request while spun down, starting.\n"); atadev->spindown_state = 0; request->timeout = 31; - } else { + } + else { request->timeout = 5; } request->retries = 2; @@ -426,7 +398,105 @@ ad_init(device_t dev) atadev->max_iosize = DEV_BSIZE; } -void +static void +ad_get_geometry(device_t dev) +{ + struct ata_device *atadev = device_get_softc(dev); + struct ad_softc *adp = device_get_ivars(dev); + u_int64_t lbasize48; + u_int32_t lbasize; + + if ((atadev->param.atavalid & ATA_FLAG_54_58) && + atadev->param.current_heads && atadev->param.current_sectors) { + adp->heads = atadev->param.current_heads; + adp->sectors = atadev->param.current_sectors; + adp->total_secs = (u_int32_t)atadev->param.current_size_1 | + ((u_int32_t)atadev->param.current_size_2 << 16); + } + else { + adp->heads = atadev->param.heads; + adp->sectors = atadev->param.sectors; + adp->total_secs = atadev->param.cylinders * adp->heads * adp->sectors; + } + lbasize = (u_int32_t)atadev->param.lba_size_1 | + ((u_int32_t)atadev->param.lba_size_2 << 16); + + /* does this device need oldstyle CHS addressing */ + if (!ad_version(atadev->param.version_major) || !lbasize) + atadev->flags |= ATA_D_USE_CHS; + + /* use the 28bit LBA size if valid or bigger than the CHS mapping */ + if (atadev->param.cylinders == 16383 || adp->total_secs < lbasize) + adp->total_secs = lbasize; + + /* use the 48bit LBA size if valid */ + lbasize48 = ((u_int64_t)atadev->param.lba_size48_1) | + ((u_int64_t)atadev->param.lba_size48_2 << 16) | + ((u_int64_t)atadev->param.lba_size48_3 << 32) | + ((u_int64_t)atadev->param.lba_size48_4 << 48); + if ((atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) && + lbasize48 > ATA_MAX_28BIT_LBA) + adp->total_secs = lbasize48; +} + +static void +ad_set_geometry(device_t dev) +{ + struct ad_softc *adp = device_get_ivars(dev); + struct ata_request *request; + + if (1 | bootverbose) + device_printf(dev, "ORG %ju sectors [%juC/%dH/%dS]\n", adp->total_secs, + adp->total_secs / (adp->heads * adp->sectors), + adp->heads, adp->sectors); + + if (!(request = ata_alloc_request())) + return; + + /* get the max native size the device supports */ + request->dev = dev; + request->u.ata.command = ATA_READ_NATIVE_MAX_ADDRESS; + request->u.ata.lba = 0; + request->u.ata.count = 0; + request->u.ata.feature = 0; + request->flags = ATA_R_CONTROL | ATA_R_QUIET; + request->timeout = 5; + request->retries = 0; + ata_queue_request(request); + if (request->status & ATA_S_ERROR) + goto out; + + if (1 | bootverbose) + device_printf(dev, "MAX %ju sectors\n", request->u.ata.lba + 1); + + /* if original size equals max size nothing more todo */ + if (adp->total_secs >= request->u.ata.lba) + goto out; + + /* set the max native size to its max */ + request->dev = dev; + request->u.ata.command = ATA_SET_MAX_ADDRESS; + request->u.ata.count = 1; + request->u.ata.feature = 0; + request->flags = ATA_R_CONTROL; + request->timeout = 5; + request->retries = 0; + ata_queue_request(request); + if (request->status & ATA_S_ERROR) + goto out; + + /* refresh geometry from drive */ + ata_getparam(device_get_softc(dev), 0); + ad_get_geometry(dev); + if (1 | bootverbose) + device_printf(dev, "NEW %ju sectors [%juC/%dH/%dS]\n", adp->total_secs, + adp->total_secs / (adp->heads * adp->sectors), + adp->heads, adp->sectors); +out: + ata_free_request(request); +} + +static void ad_describe(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); @@ -458,8 +528,7 @@ ad_describe(device_t dev) device_printf(dev, "%juMB <%s%s %.8s> at ata%d-%s %s%s\n", adp->total_secs / (1048576 / DEV_BSIZE), vendor, product, atadev->param.revision, - device_get_unit(ch->dev), - (atadev->unit == ATA_MASTER) ? "master" : "slave", + device_get_unit(ch->dev), ata_unit2str(atadev), (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", ata_mode2str(atadev->mode)); if (bootverbose) { diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h index 562b32f..3a091b4 100644 --- a/sys/dev/ata/ata-disk.h +++ b/sys/dev/ata/ata-disk.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index e6cdff5..10db9aa 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,11 +45,11 @@ __FBSDID("$FreeBSD$"); #include <dev/ata/ata-pci.h> /* prototypes */ -static void ata_dmaalloc(device_t); -static void ata_dmafree(device_t); -static void ata_dmasetprd(void *, bus_dma_segment_t *, int, int); -static int ata_dmaload(device_t, caddr_t, int32_t, int, void *, int *); -static int ata_dmaunload(device_t); +static void ata_dmaalloc(device_t dev); +static void ata_dmafree(device_t dev); +static void ata_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); +static int ata_dmaload(struct ata_request *request, void *addr, int *nsegs); +static int ata_dmaunload(struct ata_request *request); /* local vars */ static MALLOC_DEFINE(M_ATADMA, "ata_dma", "ATA driver DMA"); @@ -68,93 +68,63 @@ ata_dmainit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); - if ((ch->dma = malloc(sizeof(struct ata_dma), M_ATADMA, M_NOWAIT|M_ZERO))) { - ch->dma->alloc = ata_dmaalloc; - ch->dma->free = ata_dmafree; - ch->dma->setprd = ata_dmasetprd; - ch->dma->load = ata_dmaload; - ch->dma->unload = ata_dmaunload; - ch->dma->alignment = 2; - ch->dma->boundary = 65536; - ch->dma->segsize = 128 * DEV_BSIZE; - ch->dma->max_iosize = 128 * DEV_BSIZE; - ch->dma->max_address = BUS_SPACE_MAXADDR_32BIT; - } + ch->dma.alloc = ata_dmaalloc; + ch->dma.free = ata_dmafree; + ch->dma.setprd = ata_dmasetprd; + ch->dma.load = ata_dmaload; + ch->dma.unload = ata_dmaunload; + ch->dma.alignment = 2; + ch->dma.boundary = 65536; + ch->dma.segsize = 63536; + ch->dma.max_iosize = 128 * DEV_BSIZE; + ch->dma.max_address = BUS_SPACE_MAXADDR_32BIT; } static void ata_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { - struct ata_dc_cb_args *cba = (struct ata_dc_cb_args *)xsc; + struct ata_dc_cb_args *dcba = (struct ata_dc_cb_args *)xsc; - if (!(cba->error = error)) - cba->maddr = segs[0].ds_addr; + if (!(dcba->error = error)) + dcba->maddr = segs[0].ds_addr; } static void ata_dmaalloc(device_t dev) { struct ata_channel *ch = device_get_softc(dev); - struct ata_dc_cb_args ccba; - - if (bus_dma_tag_create(bus_get_dma_tag(dev), ch->dma->alignment, 0, - ch->dma->max_address, BUS_SPACE_MAXADDR, - NULL, NULL, ch->dma->max_iosize, - ATA_DMA_ENTRIES, ch->dma->segsize, - 0, NULL, NULL, &ch->dma->dmatag)) - goto error; - - if (bus_dma_tag_create(ch->dma->dmatag, PAGE_SIZE, PAGE_SIZE, - ch->dma->max_address, BUS_SPACE_MAXADDR, - NULL, NULL, MAXTABSZ, 1, MAXTABSZ, - 0, NULL, NULL, &ch->dma->sg_tag)) - goto error; - - if (bus_dma_tag_create(ch->dma->dmatag,ch->dma->alignment,ch->dma->boundary, - ch->dma->max_address, BUS_SPACE_MAXADDR, - NULL, NULL, ch->dma->max_iosize, - ATA_DMA_ENTRIES, ch->dma->segsize, - 0, NULL, NULL, &ch->dma->data_tag)) - goto error; - - 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->sg_tag, ch->dma->sg_map, ch->dma->sg, - MAXTABSZ, ata_dmasetupc_cb, &ccba, 0) || ccba.error) { - bus_dmamem_free(ch->dma->sg_tag, ch->dma->sg, ch->dma->sg_map); - goto error; - } - ch->dma->sg_bus = ccba.maddr; + struct ata_dc_cb_args dcba; - if (bus_dmamap_create(ch->dma->data_tag, 0, &ch->dma->data_map)) + if (bus_dma_tag_create(bus_get_dma_tag(dev), ch->dma.alignment, 0, + ch->dma.max_address, BUS_SPACE_MAXADDR, + NULL, NULL, ch->dma.max_iosize, + ATA_DMA_ENTRIES, ch->dma.segsize, + 0, NULL, NULL, &ch->dma.dmatag)) goto error; - if (bus_dma_tag_create(ch->dma->dmatag, PAGE_SIZE, 64 * 1024, - ch->dma->max_address, BUS_SPACE_MAXADDR, + if (bus_dma_tag_create(ch->dma.dmatag, PAGE_SIZE, 64 * 1024, + ch->dma.max_address, BUS_SPACE_MAXADDR, NULL, NULL, MAXWSPCSZ, 1, MAXWSPCSZ, - 0, NULL, NULL, &ch->dma->work_tag)) + 0, NULL, NULL, &ch->dma.work_tag)) goto error; - if (bus_dmamem_alloc(ch->dma->work_tag, (void **)&ch->dma->work, 0, - &ch->dma->work_map)) + 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->work_tag, ch->dma->work_map,ch->dma->work, - MAXWSPCSZ, ata_dmasetupc_cb, &ccba, 0) || ccba.error) { - bus_dmamem_free(ch->dma->work_tag,ch->dma->work, ch->dma->work_map); + if (bus_dmamap_load(ch->dma.work_tag, ch->dma.work_map ,ch->dma.work, + MAXWSPCSZ, ata_dmasetupc_cb, &dcba, BUS_DMA_NOWAIT) || + dcba.error) { + bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); goto error; } - ch->dma->work_bus = ccba.maddr; + ch->dma.work_bus = dcba.maddr; return; error: device_printf(dev, "WARNING - DMA allocation failed, disabling DMA\n"); ata_dmafree(dev); - free(ch->dma, M_ATADMA); - ch->dma = NULL; } static void @@ -162,39 +132,20 @@ ata_dmafree(device_t dev) { struct ata_channel *ch = device_get_softc(dev); - 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->work_tag) { - bus_dma_tag_destroy(ch->dma->work_tag); - ch->dma->work_tag = 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->data_map) { - bus_dmamap_destroy(ch->dma->data_tag, ch->dma->data_map); - ch->dma->data_map = NULL; - } - if (ch->dma->sg_tag) { - bus_dma_tag_destroy(ch->dma->sg_tag); - ch->dma->sg_tag = 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->data_tag) { - bus_dma_tag_destroy(ch->dma->data_tag); - ch->dma->data_tag = NULL; + if (ch->dma.work_tag) { + bus_dma_tag_destroy(ch->dma.work_tag); + ch->dma.work_tag = NULL; } - if (ch->dma->dmatag) { - bus_dma_tag_destroy(ch->dma->dmatag); - ch->dma->dmatag = NULL; + if (ch->dma.dmatag) { + bus_dma_tag_destroy(ch->dma.dmatag); + ch->dma.dmatag = NULL; } } @@ -218,67 +169,144 @@ ata_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) } static int -ata_dmaload(device_t dev, caddr_t data, int32_t count, int dir, - void *addr, int *entries) +ata_dmaload(struct ata_request *request, void *addr, int *entries) { - struct ata_channel *ch = device_get_softc(dev); - struct ata_dmasetprd_args cba; + struct ata_channel *ch = device_get_softc(request->parent); + struct ata_dc_cb_args dcba; + struct ata_dmasetprd_args dspa; int error; - if (ch->dma->flags & ATA_DMA_LOADED) { - device_printf(dev, "FAILURE - already active DMA on this device\n"); + ATA_DEBUG_RQ(request, "dmaload"); + + if (request->dma.cur_iosize) { + device_printf(request->dev, + "FAILURE - already active DMA on this device\n"); return EIO; } - if (!count) { - device_printf(dev, "FAILURE - zero length DMA transfer attempted\n"); + if (!request->bytecount) { + device_printf(request->dev, + "FAILURE - zero length DMA transfer attempted\n"); return EIO; } - if (((uintptr_t)data & (ch->dma->alignment - 1)) || - (count & (ch->dma->alignment - 1))) { - device_printf(dev, "FAILURE - non aligned DMA transfer attempted\n"); + if (((uintptr_t)(request->data) & (ch->dma.alignment - 1)) || + (request->bytecount & (ch->dma.alignment - 1))) { + device_printf(request->dev, + "FAILURE - non aligned DMA transfer attempted\n"); return EIO; } - if (count > ch->dma->max_iosize) { - device_printf(dev, "FAILURE - oversized DMA transfer attempt %d > %d\n", - count, ch->dma->max_iosize); + if (request->bytecount > ch->dma.max_iosize) { + device_printf(request->dev, + "FAILURE - oversized DMA transfer attempt %d > %d\n", + request->bytecount, ch->dma.max_iosize); return EIO; } - cba.dmatab = addr; + if (bus_dma_tag_create(ch->dma.dmatag, PAGE_SIZE, PAGE_SIZE, + ch->dma.max_address, BUS_SPACE_MAXADDR, + NULL, NULL, MAXTABSZ, 1, MAXTABSZ, + 0, NULL, NULL, &request->dma.sg_tag)) { + device_printf(request->dev, "FAILURE - create sg_tag\n"); + goto error; + } + + if (bus_dmamem_alloc(request->dma.sg_tag, (void **)&request->dma.sg, 0, + &request->dma.sg_map)) { + device_printf(request->dev, "FAILURE - alloc sg_map\n"); + goto error; + } + + if (bus_dmamap_load(request->dma.sg_tag, request->dma.sg_map, + request->dma.sg, MAXTABSZ, + ata_dmasetupc_cb, &dcba, BUS_DMA_NOWAIT) || dcba.error){ + bus_dmamem_free(request->dma.sg_tag, + request->dma.sg, request->dma.sg_map); + device_printf(request->dev, "FAILURE - load sg\n"); + goto error; + } + request->dma.sg_bus = dcba.maddr; + + if (bus_dma_tag_create(ch->dma.dmatag, ch->dma.alignment, ch->dma.boundary, + ch->dma.max_address, BUS_SPACE_MAXADDR, + NULL, NULL, ch->dma.max_iosize, + ATA_DMA_ENTRIES, ch->dma.segsize, + BUS_DMA_ALLOCNOW, NULL, NULL, + &request->dma.data_tag)) { + device_printf(request->dev, "FAILURE - create data_tag\n"); + goto error; + } + + if (bus_dmamap_create(request->dma.data_tag, 0, &request->dma.data_map)) { + device_printf(request->dev, "FAILURE - create data_map\n"); + goto error; + } + + if (addr) + dspa.dmatab = addr; + else + dspa.dmatab = request->dma.sg; + + if ((error = bus_dmamap_load(request->dma.data_tag, request->dma.data_map, + request->data, request->bytecount, + ch->dma.setprd, &dspa, BUS_DMA_NOWAIT)) || + (error = dspa.error)) { + device_printf(request->dev, "FAILURE - load data\n"); + goto error; + } - if ((error = bus_dmamap_load(ch->dma->data_tag, ch->dma->data_map, - data, count, ch->dma->setprd, &cba, - BUS_DMA_NOWAIT)) || (error = cba.error)) - return error; + if (entries) + *entries = dspa.nsegs; - *entries = cba.nsegs; + bus_dmamap_sync(request->dma.sg_tag, request->dma.sg_map, + BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(ch->dma->sg_tag, ch->dma->sg_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(request->dma.data_tag, request->dma.data_map, + (request->flags & ATA_R_READ) ? + BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(ch->dma->data_tag, ch->dma->data_map, - dir ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); + request->dma.cur_iosize = request->bytecount; - ch->dma->cur_iosize = count; - ch->dma->flags = dir ? (ATA_DMA_LOADED | ATA_DMA_READ) : ATA_DMA_LOADED; return 0; + +error: + ata_dmaunload(request); + return EIO; } int -ata_dmaunload(device_t dev) +ata_dmaunload(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(dev); + ATA_DEBUG_RQ(request, "dmaunload"); - if (ch->dma->flags & ATA_DMA_LOADED) { - bus_dmamap_sync(ch->dma->sg_tag, ch->dma->sg_map, + if (request->dma.cur_iosize) { + bus_dmamap_sync(request->dma.sg_tag, request->dma.sg_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_sync(ch->dma->data_tag, ch->dma->data_map, - (ch->dma->flags & ATA_DMA_READ) ? + bus_dmamap_sync(request->dma.data_tag, request->dma.data_map, + (request->flags & ATA_R_READ) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(ch->dma->data_tag, ch->dma->data_map); + bus_dmamap_unload(request->dma.data_tag, request->dma.data_map); - ch->dma->cur_iosize = 0; - ch->dma->flags &= ~ATA_DMA_LOADED; + request->dma.cur_iosize = 0; + } + if (request->dma.data_map) { + bus_dmamap_destroy(request->dma.data_tag, request->dma.data_map); + request->dma.data_map = NULL; + } + if (request->dma.data_tag) { + bus_dma_tag_destroy(request->dma.data_tag); + request->dma.data_tag = NULL; + } + if (request->dma.sg_bus) { + bus_dmamap_unload(request->dma.sg_tag, request->dma.sg_map); + bus_dmamem_free(request->dma.sg_tag, request->dma.sg, + request->dma.sg_map); + request->dma.sg = NULL; + request->dma.sg_bus = 0; + request->dma.sg_map = NULL; + } + if (request->dma.sg_tag) { + bus_dma_tag_destroy(request->dma.sg_tag); + request->dma.sg_tag = NULL; } return 0; } diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c index 038e2d9..3b7d86d 100644 --- a/sys/dev/ata/ata-isa.c +++ b/sys/dev/ata/ata-isa.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index af08b1a..62a5f0a 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,16 +64,19 @@ ata_generic_hw(device_t dev) ch->hw.begin_transaction = ata_begin_transaction; ch->hw.end_transaction = ata_end_transaction; ch->hw.status = ata_generic_status; + ch->hw.softreset = NULL; ch->hw.command = ata_generic_command; ch->hw.tf_read = ata_tf_read; ch->hw.tf_write = ata_tf_write; + ch->hw.pm_read = NULL; + ch->hw.pm_write = NULL; } /* must be called with ATA channel locked and state_mtx held */ int ata_begin_transaction(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); int dummy, error; @@ -133,9 +136,7 @@ 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 ((error = ch->dma->load(ch->dev, request->data, request->bytecount, - request->flags & ATA_R_READ, ch->dma->sg, - &dummy))) { + if ((error = ch->dma.load(request, NULL, &dummy))) { device_printf(request->dev, "setting up DMA failed\n"); request->result = error; goto begin_finished; @@ -150,7 +151,7 @@ ata_begin_transaction(struct ata_request *request) } /* start DMA engine */ - if (ch->dma->start && ch->dma->start(request->dev)) { + if (ch->dma.start && ch->dma.start(request)) { device_printf(request->dev, "error starting DMA\n"); request->result = EIO; goto begin_finished; @@ -161,7 +162,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 | atadev->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit)); DELAY(10); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC)) request->result = EBUSY; @@ -180,7 +181,7 @@ ata_begin_transaction(struct ata_request *request) 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 | atadev->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit)); DELAY(10); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC)) request->result = EBUSY; @@ -188,9 +189,7 @@ ata_begin_transaction(struct ata_request *request) } /* check sanity, setup SG list and DMA engine */ - if ((error = ch->dma->load(ch->dev, request->data, request->bytecount, - request->flags & ATA_R_READ, ch->dma->sg, - &dummy))) { + if ((error = ch->dma.load(request, NULL, &dummy))) { device_printf(request->dev, "setting up DMA failed\n"); request->result = error; goto begin_finished; @@ -204,7 +203,7 @@ ata_begin_transaction(struct ata_request *request) } /* start DMA engine */ - if (ch->dma->start && ch->dma->start(request->dev)) { + if (ch->dma.start && ch->dma.start(request)) { request->result = EIO; goto begin_finished; } @@ -214,8 +213,7 @@ ata_begin_transaction(struct ata_request *request) printf("ata_begin_transaction OOPS!!!\n"); begin_finished: - if (ch->dma && ch->dma->flags & ATA_DMA_LOADED) - ch->dma->unload(ch->dev); + ch->dma.unload(request); return ATA_OP_FINISHED; begin_continue: @@ -228,7 +226,7 @@ begin_continue: int ata_end_transaction(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); int length; @@ -314,19 +312,19 @@ ata_end_transaction(struct ata_request *request) case ATA_R_DMA: /* stop DMA engine and get status */ - if (ch->dma->stop) - request->dmastat = ch->dma->stop(request->dev); + if (ch->dma.stop) + request->dma.status = ch->dma.stop(request); /* did we get error or data */ if (request->status & ATA_S_ERROR) request->error = ATA_IDX_INB(ch, ATA_ERROR); - else if (request->dmastat & ATA_BMSTAT_ERROR) + else if (request->dma.status & ATA_BMSTAT_ERROR) request->status |= ATA_S_ERROR; else if (!(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* release SG list etc */ - ch->dma->unload(ch->dev); + ch->dma.unload(request); /* done with HW */ goto end_finished; @@ -426,19 +424,19 @@ ata_end_transaction(struct ata_request *request) case ATA_R_ATAPI|ATA_R_DMA: /* stop DMA engine and get status */ - if (ch->dma->stop) - request->dmastat = ch->dma->stop(request->dev); + if (ch->dma.stop) + request->dma.status = ch->dma.stop(request); /* did we get error or data */ if (request->status & (ATA_S_ERROR | ATA_S_DWF)) request->error = ATA_IDX_INB(ch, ATA_ERROR); - else if (request->dmastat & ATA_BMSTAT_ERROR) + else if (request->dma.status & ATA_BMSTAT_ERROR) request->status |= ATA_S_ERROR; else if (!(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* release SG list etc */ - ch->dma->unload(ch->dev); + ch->dma.unload(request); /* done with HW */ goto end_finished; @@ -617,7 +615,7 @@ ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask) /* if drive fails status, reselect the drive and try again */ if (status == 0xff) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit)); timeout += 1000; DELAY(1000); continue; @@ -657,11 +655,11 @@ ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask) int ata_generic_command(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); /* select device */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit)); /* ready to issue command ? */ if (ata_wait(ch, atadev, 0) < 0) { @@ -728,7 +726,7 @@ ata_generic_command(struct ata_request *request) static void ata_tf_read(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); if (atadev->flags & ATA_D_48BIT_ACTIVE) { @@ -758,7 +756,7 @@ ata_tf_read(struct ata_request *request) static void ata_tf_write(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); if (atadev->flags & ATA_D_48BIT_ACTIVE) { @@ -772,7 +770,7 @@ ata_tf_write(struct ata_request *request) ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 40); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit)); } else { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); @@ -794,7 +792,7 @@ ata_tf_write(struct ata_request *request) (request->u.ata.lba / (sectors * heads))); ATA_IDX_OUTB(ch, ATA_CYL_MSB, (request->u.ata.lba / (sectors * heads)) >> 8); - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit | + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) | (((request->u.ata.lba% (sectors * heads)) / sectors) & 0xf)); } @@ -803,7 +801,7 @@ ata_tf_write(struct ata_request *request) ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTB(ch, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | atadev->unit | + ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } @@ -812,7 +810,7 @@ ata_tf_write(struct ata_request *request) static void ata_pio_read(struct ata_request *request, int length) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); int size = min(request->transfersize, length); int resid; @@ -837,7 +835,7 @@ 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)); + struct ata_channel *ch = device_get_softc(request->parent); int size = min(request->transfersize, length); int resid; diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 6d493e2..daee8e5 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -422,23 +422,14 @@ ata_pci_allocate(device_t dev) return 0; } -void -ata_pci_hw(device_t dev) -{ - struct ata_channel *ch = device_get_softc(dev); - - ata_generic_hw(dev); - ch->hw.status = ata_pci_status; -} - -int +static int ata_pci_status(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if ((dumping || !ata_legacy(device_get_parent(dev))) && - ch->dma && ((ch->flags & ATA_ALWAYS_DMASTAT) || - (ch->dma->flags & ATA_DMA_ACTIVE))) { + ((ch->flags & ATA_ALWAYS_DMASTAT) || + (ch->dma.flags & ATA_DMA_ACTIVE))) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != @@ -455,31 +446,44 @@ ata_pci_status(device_t dev) return 1; } +void +ata_pci_hw(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_generic_hw(dev); + ch->hw.status = ata_pci_status; +} + static int -ata_pci_dmastart(device_t dev) +ata_pci_dmastart(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(request->parent); + + ATA_DEBUG_RQ(request, "dmastart"); 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->sg_bus); - ch->dma->flags |= ATA_DMA_ACTIVE; + ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, request->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) | - ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | + ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0)| ATA_BMCMD_START_STOP); return 0; } static int -ata_pci_dmastop(device_t dev) +ata_pci_dmastop(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(request->parent); int error; + ATA_DEBUG_RQ(request, "dmastop"); + ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); - ch->dma->flags &= ~ATA_DMA_ACTIVE; + ch->dma.flags &= ~ATA_DMA_ACTIVE; error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); return error; @@ -489,12 +493,16 @@ static void ata_pci_dmareset(device_t dev) { struct ata_channel *ch = device_get_softc(dev); + struct ata_request *request; ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); - ch->dma->flags &= ~ATA_DMA_ACTIVE; + ch->dma.flags &= ~ATA_DMA_ACTIVE; ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); - ch->dma->unload(dev); + if ((request = ch->running)) { + device_printf(request->dev, "DMA reset calling unload\n"); + ch->dma.unload(request); + } } void @@ -503,11 +511,9 @@ ata_pci_dmainit(device_t dev) struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); - if (ch->dma) { - ch->dma->start = ata_pci_dmastart; - ch->dma->stop = ata_pci_dmastop; - ch->dma->reset = ata_pci_dmareset; - } + ch->dma.start = ata_pci_dmastart; + ch->dma.stop = ata_pci_dmastop; + ch->dma.reset = ata_pci_dmareset; } char * @@ -603,14 +609,13 @@ ata_pcichannel_attach(device_t dev) struct ata_channel *ch = device_get_softc(dev); int error; - if (ctlr->dmainit) + if (ctlr->dmainit) { ctlr->dmainit(dev); - if (ch->dma) - ch->dma->alloc(dev); + ch->dma.alloc(dev); + } if ((error = ctlr->allocate(dev))) { - if (ch->dma) - ch->dma->free(dev); + ch->dma.free(dev); return error; } @@ -626,8 +631,7 @@ ata_pcichannel_detach(device_t dev) if ((error = ata_detach(dev))) return error; - if (ch->dma) - ch->dma->free(dev); + ch->dma.free(dev); /* XXX SOS free resources for io and ctlio ?? */ @@ -653,11 +657,8 @@ ata_pcichannel_reset(device_t dev) struct ata_channel *ch = device_get_softc(dev); /* if DMA engine present reset it */ - if (ch->dma) { - if (ch->dma->reset) - ch->dma->reset(dev); - ch->dma->unload(dev); - } + if (ch->dma.reset) + ch->dma.reset(dev); /* reset the controller HW */ if (ctlr->reset) diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index f514af8..314b333 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2003 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -460,7 +460,6 @@ int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int f int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); int ata_pci_allocate(device_t dev); void ata_pci_hw(device_t dev); -int ata_pci_status(device_t dev); void ata_pci_dmainit(device_t dev); char *ata_pcivendor2str(device_t dev); diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 9849443..763058c 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -358,8 +358,8 @@ ata_completed(void *context, int dummy) "\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); + (request->dma.status & ATA_BMSTAT_ERROR)) + printf(" dma=0x%02x", request->dma.status); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); @@ -694,11 +694,13 @@ ata_cmd2str(struct ata_request *request) case 0x24: return ("READ48"); case 0x25: return ("READ_DMA48"); case 0x26: return ("READ_DMA_QUEUED48"); + case 0x27: return ("READ_NATIVE_MAX_ADDRESS48"); case 0x29: return ("READ_MUL48"); case 0x30: return ("WRITE"); case 0x34: return ("WRITE48"); case 0x35: return ("WRITE_DMA48"); case 0x36: return ("WRITE_DMA_QUEUED48"); + case 0x37: return ("SET_MAX_ADDRESS48"); case 0x39: return ("WRITE_MUL48"); case 0x70: return ("SEEK"); case 0xa0: return ("PACKET_CMD"); @@ -727,6 +729,9 @@ ata_cmd2str(struct ata_request *request) } sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature); return buffer; + case 0xf5: return ("SECURITY_FREE_LOCK"); + case 0xf8: return ("READ_NATIVE_MAX_ADDRESS"); + case 0xf9: return ("SET_MAX_ADDRESS"); } } sprintf(buffer, "unknown CMD (0x%02x)", request->u.ata.command); diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 74c849c..50a872b 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2000 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 17d38e4..f8cc2b9 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2000 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/ata-usb.c b/sys/dev/ata/ata-usb.c index cc449e0..2cc25d6 100644 --- a/sys/dev/ata/ata-usb.c +++ b/sys/dev/ata/ata-usb.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2006 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2006 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$"); #include <sys/ata.h> #include <sys/bus.h> #include <sys/endian.h> -#include <sys/sysctl.h> #include <sys/malloc.h> #include <sys/module.h> #include <sys/sema.h> diff --git a/sys/dev/ata/ata_if.m b/sys/dev/ata/ata_if.m index 2621fef..8fcc3f2 100644 --- a/sys/dev/ata/ata_if.m +++ b/sys/dev/ata/ata_if.m @@ -1,4 +1,4 @@ -# Copyright (c) 2004 - 2007 Søren Schmidt <sos@FreeBSD.org> +# Copyright (c) 2004 - 2008 Søren Schmidt <sos@FreeBSD.org> # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index df63fe1..a64cfeb 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -908,10 +908,7 @@ acd_set_ioparm(device_t dev) struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct acd_softc *cdp = device_get_ivars(dev); - if (ch->dma) - cdp->iomax = min(ch->dma->max_iosize, 65534); - else - cdp->iomax = min(DFLTPHYS, 65534); + cdp->iomax = min(ch->dma.max_iosize, 65534); } static void @@ -1706,8 +1703,7 @@ acd_describe(device_t dev) (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM":"CDROM", - device_get_unit(ch->dev), - (atadev->unit == ATA_MASTER) ? "master" : "slave"); + device_get_unit(ch->dev), ata_unit2str(atadev)); device_printf(dev, "%s", ""); if (cdp->cap.cur_read_speed) { @@ -1879,8 +1875,7 @@ acd_describe(device_t dev) printf("with %d CD changer ", cdp->changer_info->slots); printf("<%.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", + device_get_unit(ch->dev), ata_unit2str(atadev), ata_mode2str(atadev->mode) ); } } diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h index 3358870..d78771a 100644 --- a/sys/dev/ata/atapi-cd.h +++ b/sys/dev/ata/atapi-cd.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index 0f98913..9a26399 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,10 +105,7 @@ afd_attach(device_t dev) fdp->disk->d_ioctl = afd_ioctl; fdp->disk->d_name = "afd"; 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_maxsize = ch->dma.max_iosize; fdp->disk->d_unit = device_get_unit(dev); disk_create(fdp->disk, DISK_VERSION); return 0; @@ -406,8 +403,7 @@ afd_describe(device_t dev) device_printf(dev, "%s <%.40s %.8s> at ata%d-%s %s\n", sizestring, atadev->param.model, atadev->param.revision, - device_get_unit(ch->dev), - (atadev->unit == ATA_MASTER) ? "master" : "slave", + device_get_unit(ch->dev), ata_unit2str(atadev), ata_mode2str(atadev->mode)); if (bootverbose) { device_printf(dev, "%ju sectors [%juC/%dH/%dS]\n", diff --git a/sys/dev/ata/atapi-fd.h b/sys/dev/ata/atapi-fd.h index fdad69b..e44ad66 100644 --- a/sys/dev/ata/atapi-fd.h +++ b/sys/dev/ata/atapi-fd.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c index f12f4b4..3304907 100644 --- a/sys/dev/ata/atapi-tape.c +++ b/sys/dev/ata/atapi-tape.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -142,19 +142,13 @@ ast_attach(device_t dev) UID_ROOT, GID_OPERATOR, 0640, "ast%d", device_get_unit(dev)); device->si_drv1 = dev; - if (ch->dma) - device->si_iosize_max = ch->dma->max_iosize; - else - device->si_iosize_max = DFLTPHYS; + device->si_iosize_max = ch->dma.max_iosize; stp->dev1 = device; device = make_dev(&ast_cdevsw, 2 * device_get_unit(dev) + 1, UID_ROOT, GID_OPERATOR, 0640, "nast%d", device_get_unit(dev)); device->si_drv1 = dev; - if (ch->dma) - device->si_iosize_max = ch->dma->max_iosize; - else - device->si_iosize_max = DFLTPHYS; + device->si_iosize_max = ch->dma.max_iosize; stp->dev2 = device; /* announce we are here and ready */ @@ -678,8 +672,7 @@ ast_describe(device_t dev) if (bootverbose) { device_printf(dev, "<%.40s/%.8s> tape 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_get_unit(ch->dev), ata_unit2str(atadev)); device_printf(dev, "%dKB/s, ", stp->cap.max_speed); printf("transfer limit %d blk%s, ", stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : ""); @@ -717,8 +710,7 @@ ast_describe(device_t dev) else { device_printf(dev, "TAPE <%.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", + device_get_unit(ch->dev), ata_unit2str(atadev), ata_mode2str(atadev->mode)); } } diff --git a/sys/dev/ata/atapi-tape.h b/sys/dev/ata/atapi-tape.h index af3ea23..0d4dedf 100644 --- a/sys/dev/ata/atapi-tape.h +++ b/sys/dev/ata/atapi-tape.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/sys/ata.h b/sys/sys/ata.h index d951ceb..a42932c 100644 --- a/sys/sys/ata.h +++ b/sys/sys/ata.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2006 Søren Schmidt <sos@FreeBSD.org> + * Copyright (c) 2000 - 2008 Søren Schmidt <sos@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -239,7 +239,7 @@ struct ata_params { #define ATA_READ48 0x24 /* read 48bit LBA */ #define ATA_READ_DMA48 0x25 /* read DMA 48bit LBA */ #define ATA_READ_DMA_QUEUED48 0x26 /* read DMA QUEUED 48bit LBA */ -#define ATA_READ_NATIVE_MAX_ADDDRESS48 0x27 /* read native max addr 48bit */ +#define ATA_READ_NATIVE_MAX_ADDRESS48 0x27 /* read native max addr 48bit */ #define ATA_READ_MUL48 0x29 /* read multi 48bit LBA */ #define ATA_WRITE 0x30 /* write */ #define ATA_WRITE48 0x34 /* write 48bit LBA */ @@ -267,8 +267,10 @@ struct ata_params { #define ATA_STANDBY_CMD 0xe2 /* standby */ #define ATA_IDLE_CMD 0xe3 /* idle */ #define ATA_READ_BUFFER 0xe4 /* read buffer */ +#define ATA_READ_PM 0xe4 /* read portmultiplier */ #define ATA_SLEEP 0xe6 /* sleep */ #define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */ +#define ATA_WRITE_PM 0xe8 /* write portmultiplier */ #define ATA_FLUSHCACHE48 0xea /* flush cache to disk */ #define ATA_ATA_IDENTIFY 0xec /* get ATA params */ #define ATA_SETFEATURES 0xef /* features command */ @@ -282,7 +284,7 @@ struct ata_params { #define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */ #define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */ #define ATA_SECURITY_FREEE_LOCK 0xf5 /* freeze security config */ -#define ATA_READ_NATIVE_MAX_ADDDRESS 0xf8 /* read native max address */ +#define ATA_READ_NATIVE_MAX_ADDRESS 0xf8 /* read native max address */ #define ATA_SET_MAX_ADDRESS 0xf9 /* set max address */ |