Now that probing is working in the new fashion, we need to go back to

having ata_getparm issue an ata_request and not fool around with the HW
on its own.
Needed for new HW support.
This commit is contained in:
sos 2005-04-29 11:30:03 +00:00
parent cc6dd6e064
commit 44e51c4adc
4 changed files with 166 additions and 194 deletions

View File

@ -68,7 +68,10 @@ static struct cdevsw ata_cdevsw = {
/* prototypes */
static void ata_interrupt(void *);
static void ata_boot_attach(void);
static device_t ata_add_child(device_t parent, struct ata_device *atadev, int unit);
static device_t ata_add_child(device_t, struct ata_device *, int);
static void bswap(int8_t *, int);
static void btrim(int8_t *, int);
static void bpack(int8_t *, int8_t *, int);
/* global vars */
MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer");
@ -566,7 +569,6 @@ ata_boot_attach(void)
static device_t
ata_add_child(device_t parent, struct ata_device *atadev, int unit)
{
struct ata_channel *ch = device_get_softc(parent);
device_t child;
if ((child = device_add_child(parent, NULL, unit))) {
@ -580,83 +582,146 @@ ata_add_child(device_t parent, struct ata_device *atadev, int unit)
atadev->dev = child;
atadev->max_iosize = DEV_BSIZE;
atadev->mode = ATA_PIO_MAX;
}
return child;
}
static int
ata_getparam(device_t parent, struct ata_device *atadev)
{
struct ata_channel *ch = device_get_softc(parent);
struct ata_request *request;
u_int8_t command = 0;
int error = ENOMEM, retries = 2;
if (ch->devices &
(atadev->unit == ATA_MASTER ? ATA_ATA_MASTER : ATA_ATA_SLAVE))
command = ATA_ATA_IDENTIFY;
if (ch->devices &
(atadev->unit == ATA_MASTER ? ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE))
command = ATA_ATAPI_IDENTIFY;
if (!command)
return ENXIO;
while (retries-- > 0 && error) {
if (!(request = ata_alloc_request()))
break;
request->dev = atadev->dev;
request->timeout = 1;
request->retries = 0;
request->u.ata.command = command;
request->flags = (ATA_R_READ|ATA_R_AT_HEAD|ATA_R_DIRECT|ATA_R_QUIET);
request->data = (void *)&atadev->param;
request->bytecount = sizeof(struct ata_params);
request->donecount = 0;
request->transfersize = DEV_BSIZE;
ata_queue_request(request);
error = request->result;
ata_free_request(request);
}
if (!error && (isprint(atadev->param.model[0]) ||
isprint(atadev->param.model[1]))) {
struct ata_params *atacap = &atadev->param;
#if BYTE_ORDER == BIG_ENDIAN
int16_t *ptr;
for (ptr = (int16_t *)atacap;
ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) {
*ptr = bswap16(*ptr);
}
#endif
if (!(!strncmp(atacap->model, "FX", 2) ||
!strncmp(atacap->model, "NEC", 3) ||
!strncmp(atacap->model, "Pioneer", 7) ||
!strncmp(atacap->model, "SHARP", 5))) {
bswap(atacap->model, sizeof(atacap->model));
bswap(atacap->revision, sizeof(atacap->revision));
bswap(atacap->serial, sizeof(atacap->serial));
}
btrim(atacap->model, sizeof(atacap->model));
bpack(atacap->model, atacap->model, sizeof(atacap->model));
btrim(atacap->revision, sizeof(atacap->revision));
bpack(atacap->revision, atacap->revision, sizeof(atacap->revision));
btrim(atacap->serial, sizeof(atacap->serial));
bpack(atacap->serial, atacap->serial, sizeof(atacap->serial));
if (bootverbose)
printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n",
ch->unit, atadev->unit == ATA_MASTER ? "master":"slave",
ata_mode2str(ata_pmode(atacap)),
ata_mode2str(ata_wmode(atacap)),
ata_mode2str(ata_umode(atacap)),
(atacap->hwres & ATA_CABLE_ID) ? "80":"40");
if (atadev->param.config & ATA_PROTO_ATAPI) {
if (atapi_dma && ch->dma &&
if (atapi_dma && ch->dma &&
(atadev->param.config & ATA_DRQ_MASK) != ATA_DRQ_INTR &&
ata_umode(&atadev->param) >= ATA_UDMA2)
ata_umode(&atadev->param) >= ATA_UDMA2)
atadev->mode = ATA_DMA_MAX;
}
else {
else {
if (ata_dma && ch->dma)
atadev->mode = ATA_DMA_MAX;
}
}
return child;
else {
if (!error)
error = ENXIO;
}
return error;
}
int
ata_identify(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
struct ata_device *master, *slave;
int master_res = EIO, slave_res = EIO, master_unit = -1, slave_unit = -1;
struct ata_device *master = NULL, *slave = NULL;
device_t master_child = NULL, slave_child = NULL;
int master_unit = -1, slave_unit = -1;
if (!(master = malloc(sizeof(struct ata_device),
M_ATA, M_NOWAIT | M_ZERO))) {
device_printf(dev, "out of memory\n");
return ENOMEM;
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;
}
master->unit = ATA_MASTER;
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;
/* wait for the channel to be IDLE then grab it before touching HW */
while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit)
tsleep(ch, PRIBIO, "ataidnt1", 1);
while (1) {
mtx_lock(&ch->state_mtx);
if (ch->state == ATA_IDLE) {
ch->state = ATA_ACTIVE;
mtx_unlock(&ch->state_mtx);
break;
}
mtx_unlock(&ch->state_mtx);
tsleep(ch, PRIBIO, "ataidnt2", 1);
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;
}
if (ch->devices & ATA_ATA_SLAVE) {
slave_res = ata_getparam(dev, slave, ATA_ATA_IDENTIFY);
#ifdef ATA_STATIC_ID
slave_unit = (device_get_unit(dev) << 1) + 1;
#endif
}
else if (ch->devices & ATA_ATAPI_SLAVE)
slave_res = ata_getparam(dev, slave, ATA_ATAPI_IDENTIFY);
if (ch->devices & ATA_ATA_MASTER) {
master_res = ata_getparam(dev, master, ATA_ATA_IDENTIFY);
#ifdef ATA_STATIC_ID
if (ch->devices & ATA_ATA_MASTER)
master_unit = (device_get_unit(dev) << 1);
#endif
}
else if (ch->devices & ATA_ATAPI_MASTER)
master_res = ata_getparam(dev, master, ATA_ATAPI_IDENTIFY);
if (master_res || !ata_add_child(dev, master, master_unit))
if (master && !(master_child = ata_add_child(dev, master, master_unit))) {
free(master, M_ATA);
if (slave_res || !ata_add_child(dev, slave, slave_unit))
master = NULL;
}
#ifdef ATA_STATIC_ID
if (ch->devices & ATA_ATA_SLAVE)
slave_unit = (device_get_unit(dev) << 1) + 1;
#endif
if (slave && !(slave_child = ata_add_child(dev, slave, slave_unit))) {
free(slave, M_ATA);
slave = NULL;
}
mtx_lock(&ch->state_mtx);
ch->state = ATA_IDLE;
mtx_unlock(&ch->state_mtx);
ATA_LOCKING(dev, ATA_LF_UNLOCK);
if (slave && ata_getparam(dev, slave)) {
device_delete_child(dev, slave_child);
free(slave, M_ATA);
}
if (master && ata_getparam(dev, master)) {
device_delete_child(dev, master_child);
free(master, M_ATA);
}
bus_generic_probe(dev);
bus_generic_attach(dev);
@ -791,6 +856,51 @@ ata_limit_mode(struct ata_device *atadev, int mode, int maxmode)
return mode;
}
static void
bswap(int8_t *buf, int len)
{
u_int16_t *ptr = (u_int16_t*)(buf + len);
while (--ptr >= (u_int16_t*)buf)
*ptr = ntohs(*ptr);
}
static void
btrim(int8_t *buf, int len)
{
int8_t *ptr;
for (ptr = buf; ptr < buf+len; ++ptr)
if (!*ptr || *ptr == '_')
*ptr = ' ';
for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
*ptr = 0;
}
static void
bpack(int8_t *src, int8_t *dst, int len)
{
int i, j, blank;
for (i = j = blank = 0 ; i < len; i++) {
if (blank && src[i] == ' ') continue;
if (blank && src[i] != ' ') {
dst[j++] = src[i];
blank = 0;
continue;
}
if (src[i] == ' ') {
blank = 1;
if (i == 0)
continue;
}
dst[j++] = src[i];
}
if (j < len)
dst[j] = 0x00;
}
/*
* module handeling
*/

View File

@ -471,7 +471,6 @@ void ata_fail_requests(struct ata_channel *ch, device_t dev);
char *ata_cmd2str(struct ata_request *request);
/* ata-lowlevel.c: */
int ata_getparam(device_t parent, struct ata_device *atadev, u_int8_t command);
void ata_generic_hw(struct ata_channel *ch);
void ata_generic_reset(struct ata_channel *ch);
int ata_generic_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature);

View File

@ -54,100 +54,6 @@ static int ata_end_transaction(struct ata_request *);
static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t);
static void ata_pio_read(struct ata_request *, int);
static void ata_pio_write(struct ata_request *, int);
static void bswap(int8_t *, int);
static void btrim(int8_t *, int);
static void bpack(int8_t *, int8_t *, int);
/* get device parameter page from device */
int
ata_getparam(device_t parent, struct ata_device *atadev, u_int8_t command)
{
struct ata_channel *ch = device_get_softc(parent);
int error = 0, retry = 0;
do {
if (retry++ > 4) {
if (bootverbose)
printf("ata%d-%s: %s-identify retries exceeded\n", ch->unit,
atadev->unit == ATA_MASTER ? "master" : "slave",
command == ATA_ATAPI_IDENTIFY ? "ATAPI" : "ATA");
error = ENXIO;
break;
}
/* select device */
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit);
/* wait a bit to let slow devices settle */
DELAY(100);
/* disable interrupt */
ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT | ATA_A_IDS);
/* ready to issue command ? */
if ((error = ata_wait(ch, atadev, 0)) < 0) {
printf("ata%d-%s: timeout sending %s-identify error=%d\n",
device_get_unit(parent),
atadev->unit == ATA_MASTER ? "master" : "slave",
command == ATA_ATAPI_IDENTIFY ? "ATAPI" : "ATA", error);
error = ENXIO;
break;
}
/* select device */
ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit);
/* issue command */
ATA_IDX_OUTB(ch, ATA_COMMAND, command);
} while (ata_wait(ch, atadev, ATA_S_DRQ));
if (!error) {
ATA_IDX_INSW_STRM(ch, ATA_DATA, (void *)&atadev->param,
sizeof(struct ata_params)/sizeof(int16_t));
ATA_IDX_INB(ch, ATA_STATUS);
}
if (!error && (isprint(atadev->param.model[0]) ||
isprint(atadev->param.model[1]))) {
struct ata_params *atacap = &atadev->param;
#if BYTE_ORDER == BIG_ENDIAN
int16_t *ptr;
for (ptr = (int16_t *)atacap;
ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) {
*ptr = bswap16(*ptr);
}
#endif
if (!(!strncmp(atacap->model, "FX", 2) ||
!strncmp(atacap->model, "NEC", 3) ||
!strncmp(atacap->model, "Pioneer", 7) ||
!strncmp(atacap->model, "SHARP", 5))) {
bswap(atacap->model, sizeof(atacap->model));
bswap(atacap->revision, sizeof(atacap->revision));
bswap(atacap->serial, sizeof(atacap->serial));
}
btrim(atacap->model, sizeof(atacap->model));
bpack(atacap->model, atacap->model, sizeof(atacap->model));
btrim(atacap->revision, sizeof(atacap->revision));
bpack(atacap->revision, atacap->revision, sizeof(atacap->revision));
btrim(atacap->serial, sizeof(atacap->serial));
bpack(atacap->serial, atacap->serial, sizeof(atacap->serial));
if (bootverbose)
printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n",
ch->unit, atadev->unit == ATA_MASTER ? "master":"slave",
ata_mode2str(ata_pmode(atacap)),
ata_mode2str(ata_wmode(atacap)),
ata_mode2str(ata_umode(atacap)),
(atacap->hwres & ATA_CABLE_ID) ? "80":"40");
}
else {
if (!error)
error = ENXIO;
}
return error;
}
/*
* low level ATA functions
@ -948,47 +854,3 @@ ata_pio_write(struct ata_request *request, int length)
ATA_IDX_OUTW(ch, ATA_DATA, 0);
}
}
static void
bswap(int8_t *buf, int len)
{
u_int16_t *ptr = (u_int16_t*)(buf + len);
while (--ptr >= (u_int16_t*)buf)
*ptr = ntohs(*ptr);
}
static void
btrim(int8_t *buf, int len)
{
int8_t *ptr;
for (ptr = buf; ptr < buf+len; ++ptr)
if (!*ptr || *ptr == '_')
*ptr = ' ';
for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
*ptr = 0;
}
static void
bpack(int8_t *src, int8_t *dst, int len)
{
int i, j, blank;
for (i = j = blank = 0 ; i < len; i++) {
if (blank && src[i] == ' ') continue;
if (blank && src[i] != ' ') {
dst[j++] = src[i];
blank = 0;
continue;
}
if (src[i] == ' ') {
blank = 1;
if (i == 0)
continue;
}
dst[j++] = src[i];
}
if (j < len)
dst[j] = 0x00;
}

View File

@ -454,6 +454,7 @@ ata_timeout(struct ata_request *request)
if (ch->state == ATA_ACTIVE || ch->state == ATA_STALL_QUEUE) {
request->flags |= ATA_R_TIMEOUT;
ch->state |= ATA_TIMEOUT;
ch->running = NULL;
mtx_unlock(&ch->state_mtx);
ATA_LOCKING(ch->dev, ATA_LF_UNLOCK);
ata_finish(request);