ata-lowlevel.c revision 119651
1119404Ssos/*- 2119404Ssos * Copyright (c) 1998 - 2003 S�ren Schmidt <sos@FreeBSD.org> 3119404Ssos * All rights reserved. 4119404Ssos * 5119404Ssos * Redistribution and use in source and binary forms, with or without 6119404Ssos * modification, are permitted provided that the following conditions 7119404Ssos * are met: 8119404Ssos * 1. Redistributions of source code must retain the above copyright 9119404Ssos * notice, this list of conditions and the following disclaimer, 10119404Ssos * without modification, immediately at the beginning of the file. 11119404Ssos * 2. Redistributions in binary form must reproduce the above copyright 12119404Ssos * notice, this list of conditions and the following disclaimer in the 13119404Ssos * documentation and/or other materials provided with the distribution. 14119404Ssos * 3. The name of the author may not be used to endorse or promote products 15119404Ssos * derived from this software without specific prior written permission. 16119404Ssos * 17119404Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18119404Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19119404Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20119404Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21119404Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22119404Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23119404Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24119404Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25119404Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26119404Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27119404Ssos */ 28119404Ssos 29119418Sobrien#include <sys/cdefs.h> 30119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ata/ata-lowlevel.c 119651 2003-09-01 11:13:21Z sos $"); 31119418Sobrien 32119404Ssos#include "opt_ata.h" 33119404Ssos#include <sys/param.h> 34119404Ssos#include <sys/systm.h> 35119404Ssos#include <sys/ata.h> 36119404Ssos#include <sys/kernel.h> 37119404Ssos#include <sys/conf.h> 38119404Ssos#include <sys/bus.h> 39119404Ssos#include <sys/mutex.h> 40119404Ssos#include <sys/taskqueue.h> 41119404Ssos#include <machine/bus.h> 42119404Ssos#include <sys/rman.h> 43119404Ssos#include <dev/ata/ata-all.h> 44119404Ssos 45119404Ssos/* prototypes */ 46119450Ssosstatic int ata_transaction(struct ata_request *); 47119450Ssosstatic void ata_interrupt(void *); 48119450Ssosstatic void ata_reset(struct ata_channel *); 49119450Ssosstatic int ata_wait(struct ata_device *, u_int8_t); 50119450Ssosstatic int ata_command(struct ata_device *, u_int8_t, u_int64_t, u_int16_t, u_int16_t); 51119450Ssosstatic void ata_pio_read(struct ata_request *, int); 52119450Ssosstatic void ata_pio_write(struct ata_request *, int); 53119404Ssos 54119404Ssos/* local vars */ 55119404Ssosstatic int atadebug = 0; 56119404Ssos 57119404Ssos/* 58119404Ssos * low level ATA functions 59119404Ssos */ 60119404Ssosvoid 61119404Ssosata_generic_hw(struct ata_channel *ch) 62119404Ssos{ 63119404Ssos ch->hw.reset = ata_reset; 64119404Ssos ch->hw.transaction = ata_transaction; 65119404Ssos ch->hw.interrupt = ata_interrupt; 66119404Ssos} 67119404Ssos 68119404Ssos/* must be called with ATA channel locked */ 69119404Ssosstatic int 70119404Ssosata_transaction(struct ata_request *request) 71119404Ssos{ 72119404Ssos /* record the request as running */ 73119404Ssos request->device->channel->running = request; 74119404Ssos 75119404Ssos /* disable ATAPI DMA writes if HW doesn't support it */ 76119404Ssos if (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE) && 77119404Ssos request->device->channel->flags & ATA_ATAPI_DMA_RO) 78119404Ssos request->flags &= ~ATA_R_DMA; 79119404Ssos 80119404Ssos switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { 81119404Ssos 82119404Ssos /* ATA PIO data transfer and control commands */ 83119404Ssos default: 84119404Ssos { 85119404Ssos /* record command direction here as our request might be done later */ 86119404Ssos int write = (request->flags & ATA_R_WRITE); 87119404Ssos 88119404Ssos /* issue command */ 89119404Ssos if (ata_command(request->device, request->u.ata.command, 90119404Ssos request->u.ata.lba, request->u.ata.count, 91119404Ssos request->u.ata.feature)) { 92119404Ssos ata_prtdev(request->device, "error issueing PIO command\n"); 93119404Ssos request->result = EIO; 94119404Ssos return ATA_OP_FINISHED; 95119404Ssos } 96119404Ssos 97119404Ssos /* if write command output the data */ 98119404Ssos if (write) { 99119404Ssos if (ata_wait(request->device, 100119404Ssos (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { 101119404Ssos ata_prtdev(request->device,"timeout waiting for write DRQ"); 102119404Ssos request->result = EIO; 103119404Ssos return ATA_OP_FINISHED; 104119404Ssos } 105119404Ssos ata_pio_write(request, request->transfersize); 106119404Ssos } 107119404Ssos } 108119404Ssos /* return and wait for interrupt */ 109119404Ssos return ATA_OP_CONTINUES; 110119404Ssos 111119404Ssos /* ATA DMA data transfer commands */ 112119404Ssos case ATA_R_DMA: 113119404Ssos /* check sanity and setup DMA engine */ 114119404Ssos if (request->device->channel->dma->setup(request->device, 115119404Ssos request->data, 116119404Ssos request->bytecount)) { 117119404Ssos ata_prtdev(request->device, "setting up DMA failed\n"); 118119404Ssos request->result = EIO; 119119404Ssos return ATA_OP_FINISHED; 120119404Ssos } 121119404Ssos 122119404Ssos /* issue command */ 123119404Ssos if (ata_command(request->device, request->u.ata.command, 124119404Ssos request->u.ata.lba, request->u.ata.count, 125119404Ssos request->u.ata.feature)) { 126119404Ssos ata_prtdev(request->device, "error issuing DMA command\n"); 127119404Ssos request->result = EIO; 128119404Ssos return ATA_OP_FINISHED; 129119404Ssos } 130119404Ssos 131119404Ssos /* start DMA engine */ 132119404Ssos if (request->device->channel->dma->start(request->device->channel, 133119404Ssos request->data, 134119404Ssos request->bytecount, 135119404Ssos request->flags & ATA_R_READ)) { 136119404Ssos request->result = EIO; 137119404Ssos return ATA_OP_FINISHED; 138119404Ssos } 139119404Ssos /* return and wait for interrupt */ 140119404Ssos return ATA_OP_CONTINUES; 141119404Ssos 142119404Ssos /* ATAPI PIO commands */ 143119404Ssos case ATA_R_ATAPI: 144119404Ssos /* is this just a POLL DSC command ? */ 145119404Ssos if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { 146119404Ssos ATA_IDX_OUTB(request->device->channel, ATA_DRIVE, 147119404Ssos ATA_D_IBM | request->device->unit); 148119404Ssos DELAY(10); 149119404Ssos if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC)) 150119404Ssos request->result = EBUSY; 151119404Ssos return ATA_OP_FINISHED; 152119404Ssos } 153119404Ssos 154119404Ssos /* start ATAPI operation */ 155119404Ssos if (ata_command(request->device, ATA_PACKET_CMD, 156119404Ssos request->transfersize << 8, 0, 0)) { 157119404Ssos ata_prtdev(request->device, "error issuing ATA PACKET command\n"); 158119404Ssos request->result = EIO; 159119404Ssos return ATA_OP_FINISHED; 160119404Ssos } 161119404Ssos 162119404Ssos /* command interrupt device ? just return and wait for interrupt */ 163119404Ssos if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR) 164119404Ssos return ATA_OP_CONTINUES; 165119404Ssos 166119404Ssos /* wait for ready to write ATAPI command block */ 167119404Ssos { 168119404Ssos int timeout = 5000; /* might be less for fast devices */ 169119404Ssos while (timeout--) { 170119404Ssos int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON); 171119404Ssos int status = ATA_IDX_INB(request->device->channel, ATA_STATUS); 172119404Ssos 173119404Ssos if (((reason & (ATA_I_CMD | ATA_I_IN)) | 174119404Ssos (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) 175119404Ssos break; 176119404Ssos DELAY(20); 177119404Ssos } 178119404Ssos if (timeout <= 0) { 179119404Ssos ata_prtdev(request->device, 180119404Ssos "timeout waiting for ATAPI ready\n"); 181119404Ssos request->result = EIO; 182119404Ssos return ATA_OP_FINISHED; 183119404Ssos } 184119404Ssos } 185119404Ssos 186119404Ssos /* this seems to be needed for some (slow) devices */ 187119404Ssos DELAY(10); 188119404Ssos 189119404Ssos /* output actual command block */ 190119404Ssos ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA, 191119404Ssos (int16_t *)request->u.atapi.ccb, 192119404Ssos (request->device->param->config & ATA_PROTO_MASK) == 193119404Ssos ATA_PROTO_ATAPI_12 ? 6 : 8); 194119404Ssos 195119404Ssos /* return and wait for interrupt */ 196119404Ssos return ATA_OP_CONTINUES; 197119404Ssos 198119404Ssos case ATA_R_ATAPI|ATA_R_DMA: 199119404Ssos /* is this just a POLL DSC command ? */ 200119404Ssos if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { 201119404Ssos ATA_IDX_OUTB(request->device->channel, ATA_DRIVE, 202119404Ssos ATA_D_IBM | request->device->unit); 203119404Ssos DELAY(10); 204119404Ssos if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC)) 205119404Ssos request->result = EBUSY; 206119404Ssos return ATA_OP_FINISHED; 207119404Ssos } 208119404Ssos 209119404Ssos /* check sanity and setup DMA engine */ 210119404Ssos if (request->device->channel->dma->setup(request->device, 211119404Ssos request->data, 212119404Ssos request->bytecount)) { 213119404Ssos ata_prtdev(request->device, "setting up DMA failed\n"); 214119404Ssos request->result = EIO; 215119404Ssos return ATA_OP_FINISHED; 216119404Ssos } 217119404Ssos 218119404Ssos /* start ATAPI operation */ 219119404Ssos if (ata_command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) { 220119404Ssos ata_prtdev(request->device, "error issuing ATAPI packet command\n"); 221119404Ssos request->result = EIO; 222119404Ssos return ATA_OP_FINISHED; 223119404Ssos } 224119404Ssos 225119404Ssos /* wait for ready to write ATAPI command block */ 226119404Ssos { 227119404Ssos int timeout = 5000; /* might be less for fast devices */ 228119404Ssos while (timeout--) { 229119404Ssos int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON); 230119404Ssos int status = ATA_IDX_INB(request->device->channel, ATA_STATUS); 231119404Ssos 232119404Ssos if (((reason & (ATA_I_CMD | ATA_I_IN)) | 233119404Ssos (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) 234119404Ssos break; 235119404Ssos DELAY(20); 236119404Ssos } 237119404Ssos if (timeout <= 0) { 238119404Ssos ata_prtdev(request->device, 239119404Ssos "timeout waiting for ATAPI ready\n"); 240119404Ssos request->result = EIO; 241119404Ssos return ATA_OP_FINISHED; 242119404Ssos } 243119404Ssos } 244119404Ssos 245119404Ssos /* this seems to be needed for some (slow) devices */ 246119404Ssos DELAY(10); 247119404Ssos 248119404Ssos /* output actual command block */ 249119404Ssos ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA, 250119404Ssos (int16_t *)request->u.atapi.ccb, 251119404Ssos (request->device->param->config & ATA_PROTO_MASK) == 252119404Ssos ATA_PROTO_ATAPI_12 ? 6 : 8); 253119404Ssos 254119404Ssos /* start DMA engine */ 255119404Ssos if (request->device->channel->dma->start(request->device->channel, 256119404Ssos request->data, 257119404Ssos request->bytecount, 258119404Ssos request->flags & ATA_R_READ)) { 259119404Ssos request->result = EIO; 260119404Ssos return ATA_OP_FINISHED; 261119404Ssos } 262119404Ssos 263119404Ssos /* return and wait for interrupt */ 264119404Ssos return ATA_OP_CONTINUES; 265119404Ssos } 266119404Ssos} 267119404Ssos 268119404Ssosstatic void 269119404Ssosata_interrupt(void *data) 270119404Ssos{ 271119404Ssos struct ata_channel *ch = (struct ata_channel *)data; 272119404Ssos struct ata_request *request = ch->running; 273119404Ssos int length; 274119404Ssos 275119404Ssos /* if we dont have a running request shout and ignore this interrupt */ 276119404Ssos if (request == NULL) { 277119404Ssos if (bootverbose) { 278119404Ssos printf("ata%d: spurious interrupt - ", device_get_unit(ch->dev)); 279119404Ssos if (request) 280119404Ssos printf("request OK - "); 281119404Ssos printf("status=0x%02x error=0x%02x reason=0x%02x\n", 282119404Ssos ATA_IDX_INB(ch, ATA_ALTSTAT), ATA_IDX_INB(ch, ATA_ERROR), 283119404Ssos ATA_IDX_INB(ch, ATA_IREASON)); 284119404Ssos } 285119404Ssos return; 286119404Ssos } 287119404Ssos 288119404Ssos /* if device is busy it didn't interrupt */ 289119404Ssos if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { 290119404Ssos DELAY(100); 291119404Ssos if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ)) 292119404Ssos return; 293119404Ssos } 294119404Ssos 295119404Ssos /* clear interrupt and get status */ 296119404Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 297119404Ssos 298119404Ssos switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { 299119404Ssos 300119404Ssos /* ATA PIO data transfer and control commands */ 301119404Ssos default: 302119404Ssos 303119404Ssos /* if we got an error we are done with the HW */ 304119404Ssos if (request->status & ATA_S_ERROR) { 305119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 306119404Ssos break; 307119404Ssos } 308119404Ssos 309119404Ssos /* if read data get it */ 310119404Ssos if (request->flags & ATA_R_READ) 311119404Ssos ata_pio_read(request, request->transfersize); 312119404Ssos 313119404Ssos /* update how far we've gotten */ 314119404Ssos request->donecount += request->transfersize; 315119404Ssos 316119404Ssos /* do we need a scoop more ? */ 317119404Ssos if (request->bytecount > request->donecount) { 318119404Ssos 319119404Ssos /* set this transfer size according to HW capabilities */ 320119404Ssos request->transfersize = 321119424Ssos min((request->bytecount - request->donecount), 322119404Ssos request->transfersize); 323119404Ssos 324119404Ssos /* if data write command, output the data */ 325119404Ssos if (request->flags & ATA_R_WRITE) { 326119404Ssos /* if we get an error here we are done with the HW */ 327119404Ssos if (ata_wait(request->device, 328119404Ssos (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { 329119404Ssos ata_prtdev(request->device,"timeout waiting for write DRQ"); 330119404Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 331119404Ssos break; 332119404Ssos } 333119404Ssos else { 334119404Ssos /* output data and return waiting for new interrupt */ 335119404Ssos ata_pio_write(request, request->transfersize); 336119404Ssos return; 337119404Ssos } 338119404Ssos } 339119404Ssos 340119404Ssos /* if data read command, return & wait for interrupt */ 341119404Ssos else if (request->flags & ATA_R_READ) { 342119404Ssos return; 343119404Ssos } 344119404Ssos else 345119404Ssos ata_prtdev(request->device, 346119404Ssos "FAILURE - %s shouldn't loop on control cmd\n", 347119404Ssos ata_cmd2str(request)); 348119404Ssos } 349119404Ssos /* done with HW */ 350119404Ssos break; 351119404Ssos 352119404Ssos /* ATA DMA data transfer commands */ 353119404Ssos case ATA_R_DMA: 354119404Ssos /* stop DMA engine and get status */ 355119404Ssos request->dmastat = ch->dma->stop(ch); 356119404Ssos 357119404Ssos /* did we get error or data */ 358119404Ssos if (request->status & ATA_S_ERROR) 359119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 360119404Ssos else if (request->dmastat & ATA_BMSTAT_ERROR) 361119404Ssos request->status |= ATA_S_ERROR; 362119404Ssos else 363119404Ssos request->donecount = request->bytecount; 364119404Ssos 365119404Ssos /* done with HW */ 366119404Ssos break; 367119404Ssos 368119404Ssos /* ATAPI PIO commands */ 369119404Ssos case ATA_R_ATAPI: 370119404Ssos length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); 371119404Ssos 372119404Ssos switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) | 373119404Ssos (request->status & ATA_S_DRQ)) { 374119404Ssos 375119404Ssos case ATAPI_P_CMDOUT: 376119404Ssos /* this seems to be needed for some (slow) devices */ 377119404Ssos DELAY(10); 378119404Ssos 379119404Ssos if (!(request->status & ATA_S_DRQ)) { 380119404Ssos ata_prtdev(request->device, "command interrupt without DRQ\n"); 381119404Ssos request->status = ATA_S_ERROR; 382119404Ssos break; 383119404Ssos } 384119404Ssos ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, 385119404Ssos (request->device->param->config & 386119404Ssos ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8); 387119404Ssos /* return wait for interrupt */ 388119404Ssos return; 389119404Ssos 390119404Ssos case ATAPI_P_WRITE: 391119404Ssos if (request->flags & ATA_R_READ) { 392119404Ssos request->status = ATA_S_ERROR; 393119404Ssos ata_prtdev(request->device, 394119404Ssos "%s trying to write on read buffer\n", 395119404Ssos ata_cmd2str(request)); 396119404Ssos break; 397119404Ssos } 398119404Ssos ata_pio_write(request, length); 399119404Ssos request->donecount += length; 400119404Ssos 401119404Ssos /* set next transfer size according to HW capabilities */ 402119404Ssos request->transfersize = min((request->bytecount-request->donecount), 403119404Ssos request->transfersize); 404119404Ssos /* return wait for interrupt */ 405119404Ssos return; 406119404Ssos 407119404Ssos case ATAPI_P_READ: 408119404Ssos if (request->flags & ATA_R_WRITE) { 409119404Ssos request->status = ATA_S_ERROR; 410119404Ssos ata_prtdev(request->device, 411119404Ssos "%s trying to read on write buffer\n", 412119404Ssos ata_cmd2str(request)); 413119404Ssos break; 414119404Ssos } 415119404Ssos ata_pio_read(request, length); 416119404Ssos request->donecount += length; 417119404Ssos 418119404Ssos /* set next transfer size according to HW capabilities */ 419119404Ssos request->transfersize = min((request->bytecount-request->donecount), 420119404Ssos request->transfersize); 421119404Ssos /* return wait for interrupt */ 422119404Ssos return; 423119404Ssos 424119404Ssos case ATAPI_P_DONEDRQ: 425119404Ssos ata_prtdev(request->device, 426119404Ssos "WARNING - %s DONEDRQ non conformant device\n", 427119404Ssos ata_cmd2str(request)); 428119404Ssos if (request->flags & ATA_R_READ) { 429119404Ssos ata_pio_read(request, length); 430119404Ssos request->donecount += length; 431119404Ssos } 432119404Ssos else if (request->flags & ATA_R_WRITE) { 433119404Ssos ata_pio_write(request, length); 434119404Ssos request->donecount += length; 435119404Ssos } 436119404Ssos else 437119404Ssos request->status = ATA_S_ERROR; 438119404Ssos /* FALLTHROUGH */ 439119404Ssos 440119404Ssos case ATAPI_P_ABORT: 441119404Ssos case ATAPI_P_DONE: 442119404Ssos if (request->status & (ATA_S_ERROR | ATA_S_DWF)) 443119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 444119404Ssos break; 445119404Ssos 446119404Ssos default: 447119404Ssos ata_prtdev(request->device, "unknown transfer phase\n"); 448119404Ssos request->status = ATA_S_ERROR; 449119404Ssos } 450119404Ssos /* done with HW */ 451119404Ssos break; 452119404Ssos 453119404Ssos /* ATAPI DMA commands */ 454119404Ssos case ATA_R_ATAPI|ATA_R_DMA: 455119404Ssos 456119404Ssos /* stop the engine and get engine status */ 457119404Ssos request->dmastat = ch->dma->stop(ch); 458119404Ssos 459119404Ssos /* did we get error or data */ 460119404Ssos if (request->status & (ATA_S_ERROR | ATA_S_DWF)) 461119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 462119404Ssos else if (request->dmastat & ATA_BMSTAT_ERROR) 463119404Ssos request->status |= ATA_S_ERROR; 464119404Ssos else 465119404Ssos request->donecount = request->bytecount; 466119404Ssos 467119404Ssos /* done with HW */ 468119404Ssos break; 469119404Ssos } 470119404Ssos 471119404Ssos ata_finish(request); 472119404Ssos 473119404Ssos /* unlock the ATA HW for new work */ 474119404Ssos ch->running = NULL; 475119404Ssos ATA_UNLOCK_CH(ch); 476119404Ssos ch->locking(ch, ATA_LF_UNLOCK); 477119404Ssos} 478119404Ssos 479119404Ssos/* must be called with ATA channel locked */ 480119404Ssosstatic void 481119404Ssosata_reset(struct ata_channel *ch) 482119404Ssos{ 483119651Ssos u_int8_t err, lsb, msb, ostat0, ostat1; 484119404Ssos u_int8_t stat0 = 0, stat1 = 0; 485119404Ssos int mask = 0, timeout; 486119404Ssos 487119404Ssos /* do we have any signs of ATA/ATAPI HW being present ? */ 488119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 489119404Ssos DELAY(10); 490119404Ssos ostat0 = ATA_IDX_INB(ch, ATA_STATUS); 491119404Ssos if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { 492119404Ssos stat0 = ATA_S_BUSY; 493119404Ssos mask |= 0x01; 494119404Ssos } 495119404Ssos 496119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); 497119404Ssos DELAY(10); 498119404Ssos ostat1 = ATA_IDX_INB(ch, ATA_STATUS); 499119651Ssos 500119404Ssos /* in some setups we dont want to test for a slave */ 501119404Ssos if (!(ch->flags & ATA_NO_SLAVE)) { 502119404Ssos if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { 503119404Ssos stat1 = ATA_S_BUSY; 504119404Ssos mask |= 0x02; 505119404Ssos } 506119404Ssos } 507119404Ssos 508119404Ssos /* if nothing showed up no need to get any further */ 509119404Ssos /* SOS is that too strong?, we just might loose devices here XXX */ 510119404Ssos ch->devices = 0; 511119404Ssos if (!mask) 512119404Ssos return; 513119404Ssos 514119404Ssos if (bootverbose) 515119651Ssos ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", 516119404Ssos mask, ostat0, ostat1); 517119404Ssos 518119404Ssos /* reset channel */ 519119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 520119404Ssos DELAY(10); 521119404Ssos ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); 522119404Ssos DELAY(10000); 523119404Ssos ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS); 524119501Ssos DELAY(10000); 525119404Ssos 526119404Ssos /* wait for BUSY to go inactive */ 527119501Ssos for (timeout = 0; timeout < 310; timeout++) { 528119404Ssos if (stat0 & ATA_S_BUSY) { 529119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 530119404Ssos DELAY(10); 531119651Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 532119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 533119651Ssos msb = ATA_IDX_INB(ch, ATA_CYL_MSB); 534119404Ssos stat0 = ATA_IDX_INB(ch, ATA_STATUS); 535119651Ssos if (bootverbose) 536119651Ssos ata_printf(ch, ATA_MASTER, 537119651Ssos "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", 538119651Ssos stat0, err, lsb, msb); 539119651Ssos if (!(stat0 & ATA_S_BUSY) && err == ATA_E_ILI) { 540119651Ssos if (stat0 & ATA_S_READY) { 541119651Ssos ch->devices |= ATA_ATA_MASTER; 542119651Ssos } 543119651Ssos else if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { 544119404Ssos ch->devices |= ATA_ATAPI_MASTER; 545119523Ssos } 546119404Ssos } 547119404Ssos } 548119404Ssos if (stat1 & ATA_S_BUSY) { 549119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); 550119404Ssos DELAY(10); 551119651Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 552119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 553119651Ssos msb = ATA_IDX_INB(ch, ATA_CYL_MSB); 554119404Ssos stat1 = ATA_IDX_INB(ch, ATA_STATUS); 555119651Ssos if (bootverbose) 556119651Ssos ata_printf(ch, ATA_SLAVE, 557119651Ssos "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", 558119651Ssos stat0, err, lsb, msb); 559119651Ssos if (!(stat1 & ATA_S_BUSY) && err == ATA_E_ILI) { 560119651Ssos if (stat1 & ATA_S_READY) { 561119651Ssos ch->devices |= ATA_ATA_SLAVE; 562119651Ssos } 563119651Ssos else if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { 564119404Ssos ch->devices |= ATA_ATAPI_SLAVE; 565119523Ssos } 566119404Ssos } 567119404Ssos } 568119404Ssos if (mask == 0x01) /* wait for master only */ 569119523Ssos if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20)) 570119404Ssos break; 571119404Ssos if (mask == 0x02) /* wait for slave only */ 572119523Ssos if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20)) 573119404Ssos break; 574119404Ssos if (mask == 0x03) /* wait for both master & slave */ 575119651Ssos if ((!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20)) && 576119651Ssos (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20))) 577119404Ssos break; 578119501Ssos DELAY(100000); 579119404Ssos } 580119404Ssos 581119404Ssos if (stat0 & ATA_S_BUSY) 582119404Ssos mask &= ~0x01; 583119404Ssos if (stat1 & ATA_S_BUSY) 584119404Ssos mask &= ~0x02; 585119651Ssos 586119404Ssos if (bootverbose) 587119651Ssos ata_printf(ch, -1, 588119651Ssos "reset tp2 mask=%02x stat0=%02x stat1=%02x devices=0x%b\n", 589119651Ssos mask, stat0, stat1, ch->devices, 590119651Ssos "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); 591119404Ssos if (!mask) 592119404Ssos return; 593119404Ssos 594119651Ssos if (mask & 0x01 && ostat0 != 0x00 && 595119651Ssos !(ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER))) { 596119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 597119404Ssos DELAY(10); 598119404Ssos ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); 599119404Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); 600119651Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 601119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 602119404Ssos if (bootverbose) 603119651Ssos ata_printf(ch, ATA_MASTER, "ATA err=0x%02x lsb=0x%02x\n", err, lsb); 604119651Ssos if (err != 0x58 && lsb == 0xa5) 605119404Ssos ch->devices |= ATA_ATA_MASTER; 606119404Ssos } 607119651Ssos if (mask & 0x02 && ostat1 != 0x00 && 608119651Ssos !(ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))) { 609119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); 610119404Ssos DELAY(10); 611119404Ssos ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); 612119404Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); 613119651Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 614119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 615119404Ssos if (bootverbose) 616119651Ssos ata_printf(ch, ATA_SLAVE, "ATA err=0x%02x lsb=0x%02x\n", err, lsb); 617119651Ssos if (err != 0x58 && lsb == 0xa5) 618119404Ssos ch->devices |= ATA_ATA_SLAVE; 619119404Ssos } 620119651Ssos 621119404Ssos if (bootverbose) 622119651Ssos ata_printf(ch, -1, "reset tp3 devices=0x%b\n", ch->devices, 623119651Ssos "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); 624119404Ssos} 625119404Ssos 626119404Ssosstatic int 627119404Ssosata_wait(struct ata_device *atadev, u_int8_t mask) 628119404Ssos{ 629119404Ssos int timeout = 0; 630119404Ssos u_int8_t status; 631119404Ssos 632119404Ssos DELAY(1); 633119404Ssos while (timeout < 5000000) { /* timeout 5 secs */ 634119404Ssos status = ATA_IDX_INB(atadev->channel, ATA_STATUS); 635119404Ssos 636119404Ssos /* if drive fails status, reselect the drive just to be sure */ 637119404Ssos if (status == 0xff) { 638119404Ssos ata_prtdev(atadev, "WARNING no status, reselecting device\n"); 639119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); 640119404Ssos DELAY(10); 641119404Ssos status = ATA_IDX_INB(atadev->channel, ATA_STATUS); 642119404Ssos if (status == 0xff) 643119404Ssos return -1; 644119404Ssos } 645119404Ssos 646119404Ssos /* are we done ? */ 647119404Ssos if (!(status & ATA_S_BUSY)) 648119404Ssos break; 649119404Ssos 650119404Ssos if (timeout > 1000) { 651119404Ssos timeout += 1000; 652119404Ssos DELAY(1000); 653119404Ssos } 654119404Ssos else { 655119404Ssos timeout += 10; 656119404Ssos DELAY(10); 657119404Ssos } 658119404Ssos } 659119404Ssos if (timeout >= 5000000) 660119404Ssos return -1; 661119404Ssos if (!mask) 662119404Ssos return (status & ATA_S_ERROR); 663119404Ssos 664119404Ssos /* wait 50 msec for bits wanted. */ 665119404Ssos timeout = 5000; 666119404Ssos while (timeout--) { 667119404Ssos status = ATA_IDX_INB(atadev->channel, ATA_STATUS); 668119404Ssos if ((status & mask) == mask) 669119404Ssos return (status & ATA_S_ERROR); 670119404Ssos DELAY (10); 671119404Ssos } 672119404Ssos return -1; 673119404Ssos} 674119404Ssos 675119404Ssosstatic int 676119404Ssosata_command(struct ata_device *atadev, u_int8_t command, 677119404Ssos u_int64_t lba, u_int16_t count, u_int16_t feature) 678119404Ssos{ 679119404Ssos if (atadebug) 680119404Ssos ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, " 681119404Ssos "lba=%jd, count=%d, feature=%d\n", 682119404Ssos rman_get_start(atadev->channel->r_io[ATA_DATA].res), 683119404Ssos command, (intmax_t)lba, count, feature); 684119404Ssos 685119404Ssos /* select device */ 686119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); 687119404Ssos 688119404Ssos /* ready to issue command ? */ 689119404Ssos if (ata_wait(atadev, 0) < 0) { 690119404Ssos ata_prtdev(atadev, "timeout sending command=%02x\n", command); 691119404Ssos return -1; 692119404Ssos } 693119404Ssos 694119651Ssos /* enable interrupt */ 695119651Ssos ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT); 696119651Ssos 697119404Ssos /* only use 48bit addressing if needed (avoid bugs and overhead) */ 698119404Ssos if ((lba > 268435455 || count > 256) && atadev->param && 699119404Ssos atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) { 700119404Ssos 701119404Ssos /* translate command into 48bit version */ 702119404Ssos switch (command) { 703119404Ssos case ATA_READ: 704119404Ssos command = ATA_READ48; break; 705119404Ssos case ATA_READ_MUL: 706119404Ssos command = ATA_READ_MUL48; break; 707119404Ssos case ATA_READ_DMA: 708119404Ssos command = ATA_READ_DMA48; break; 709119404Ssos case ATA_READ_DMA_QUEUED: 710119404Ssos command = ATA_READ_DMA_QUEUED48; break; 711119404Ssos case ATA_WRITE: 712119404Ssos command = ATA_WRITE48; break; 713119404Ssos case ATA_WRITE_MUL: 714119404Ssos command = ATA_WRITE_MUL48; break; 715119404Ssos case ATA_WRITE_DMA: 716119404Ssos command = ATA_WRITE_DMA48; break; 717119404Ssos case ATA_WRITE_DMA_QUEUED: 718119404Ssos command = ATA_WRITE_DMA_QUEUED48; break; 719119404Ssos case ATA_FLUSHCACHE: 720119404Ssos command = ATA_FLUSHCACHE48; break; 721119404Ssos default: 722119404Ssos ata_prtdev(atadev, "can't translate cmd to 48bit version\n"); 723119404Ssos return -1; 724119404Ssos } 725119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff); 726119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff); 727119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff); 728119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff); 729119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff); 730119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); 731119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff); 732119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); 733119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff); 734119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); 735119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit); 736119404Ssos atadev->channel->flags |= ATA_48BIT_ACTIVE; 737119404Ssos } 738119404Ssos else { 739119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature); 740119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count); 741119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); 742119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); 743119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); 744119404Ssos if (atadev->flags & ATA_D_USE_CHS) 745119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, 746119404Ssos ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf)); 747119404Ssos else 748119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, 749119404Ssos ATA_D_IBM | ATA_D_LBA | atadev->unit|((lba>>24)&0xf)); 750119404Ssos atadev->channel->flags &= ~ATA_48BIT_ACTIVE; 751119404Ssos } 752119404Ssos 753119404Ssos /* issue command to controller */ 754119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); 755119404Ssos 756119404Ssos return 0; 757119404Ssos} 758119404Ssos 759119404Ssosstatic void 760119404Ssosata_pio_read(struct ata_request *request, int length) 761119404Ssos{ 762119404Ssos int size = min(request->transfersize, length); 763119404Ssos struct ata_channel *ch = request->device->channel; 764119404Ssos int resid; 765119404Ssos 766119404Ssos if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) 767119404Ssos ATA_IDX_INSW_STRM(ch, ATA_DATA, 768119404Ssos (void*)((uintptr_t)request->data+request->donecount), 769119404Ssos size / sizeof(int16_t)); 770119404Ssos else 771119404Ssos ATA_IDX_INSL_STRM(ch, ATA_DATA, 772119404Ssos (void*)((uintptr_t)request->data+request->donecount), 773119404Ssos size / sizeof(int32_t)); 774119404Ssos 775119404Ssos if (request->transfersize < length) { 776119523Ssos ata_prtdev(request->device, "WARNING - %s read data overrun %d>%d\n", 777119404Ssos ata_cmd2str(request), length, request->transfersize); 778119404Ssos for (resid = request->transfersize; resid < length; 779119404Ssos resid += sizeof(int16_t)) 780119404Ssos ATA_IDX_INW(ch, ATA_DATA); 781119404Ssos } 782119404Ssos} 783119404Ssos 784119404Ssosstatic void 785119404Ssosata_pio_write(struct ata_request *request, int length) 786119404Ssos{ 787119404Ssos int size = min(request->transfersize, length); 788119404Ssos struct ata_channel *ch = request->device->channel; 789119404Ssos int resid; 790119404Ssos 791119404Ssos if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) 792119404Ssos ATA_IDX_OUTSW_STRM(ch, ATA_DATA, 793119404Ssos (void*)((uintptr_t)request->data+request->donecount), 794119404Ssos size / sizeof(int16_t)); 795119404Ssos else 796119404Ssos ATA_IDX_OUTSL_STRM(ch, ATA_DATA, 797119404Ssos (void*)((uintptr_t)request->data+request->donecount), 798119404Ssos size / sizeof(int32_t)); 799119404Ssos 800119404Ssos if (request->transfersize < length) { 801119523Ssos ata_prtdev(request->device, "WARNING - %s write data underrun %d>%d\n", 802119404Ssos ata_cmd2str(request), length, request->transfersize); 803119404Ssos for (resid = request->transfersize; resid < length; 804119404Ssos resid += sizeof(int16_t)) 805119404Ssos ATA_IDX_OUTW(ch, ATA_DATA, 0); 806119404Ssos } 807119404Ssos} 808