ata-lowlevel.c revision 124403
1119404Ssos/*- 2124403Ssos * Copyright (c) 1998 - 2004 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 124403 2004-01-11 22:08:34Z 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> 39124403Ssos#include <sys/sema.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{ 72124403Ssos /* safety check, device might have been detached FIXME SOS */ 73124403Ssos if (!request->device->param) { 74124403Ssos request->result = ENXIO; 75124403Ssos return ATA_OP_FINISHED; 76124403Ssos } 77124403Ssos 78119404Ssos /* record the request as running */ 79119404Ssos request->device->channel->running = request; 80119404Ssos 81124403Ssos ATA_DEBUG_RQ(request, "transaction"); 82124403Ssos 83119404Ssos /* disable ATAPI DMA writes if HW doesn't support it */ 84120938Ssos if ((request->device->channel->flags & ATA_ATAPI_DMA_RO) && 85120938Ssos ((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) == 86120938Ssos (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE))) 87119404Ssos request->flags &= ~ATA_R_DMA; 88119404Ssos 89119404Ssos switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { 90119404Ssos 91119404Ssos /* ATA PIO data transfer and control commands */ 92119404Ssos default: 93119404Ssos { 94124403Ssos /* record command direction here as our request might be gone later */ 95119404Ssos int write = (request->flags & ATA_R_WRITE); 96119404Ssos 97119404Ssos /* issue command */ 98119404Ssos if (ata_command(request->device, request->u.ata.command, 99119404Ssos request->u.ata.lba, request->u.ata.count, 100119404Ssos request->u.ata.feature)) { 101119404Ssos ata_prtdev(request->device, "error issueing PIO command\n"); 102119404Ssos request->result = EIO; 103120881Ssos break; 104119404Ssos } 105119404Ssos 106119404Ssos /* if write command output the data */ 107119404Ssos if (write) { 108119404Ssos if (ata_wait(request->device, 109119404Ssos (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { 110119404Ssos ata_prtdev(request->device,"timeout waiting for write DRQ"); 111119404Ssos request->result = EIO; 112120881Ssos break; 113119404Ssos } 114119404Ssos ata_pio_write(request, request->transfersize); 115119404Ssos } 116119404Ssos } 117124403Ssos 118119404Ssos /* return and wait for interrupt */ 119119404Ssos return ATA_OP_CONTINUES; 120119404Ssos 121119404Ssos /* ATA DMA data transfer commands */ 122119404Ssos case ATA_R_DMA: 123121310Ssos /* check sanity, setup SG list and DMA engine */ 124121310Ssos if (request->device->channel->dma->load(request->device, 125121310Ssos request->data, 126121310Ssos request->bytecount, 127121310Ssos request->flags & ATA_R_READ)) { 128119404Ssos ata_prtdev(request->device, "setting up DMA failed\n"); 129119404Ssos request->result = EIO; 130120881Ssos break; 131119404Ssos } 132119404Ssos 133119404Ssos /* issue command */ 134119404Ssos if (ata_command(request->device, request->u.ata.command, 135119404Ssos request->u.ata.lba, request->u.ata.count, 136119404Ssos request->u.ata.feature)) { 137119404Ssos ata_prtdev(request->device, "error issuing DMA command\n"); 138119404Ssos request->result = EIO; 139120881Ssos break; 140119404Ssos } 141119404Ssos 142119404Ssos /* start DMA engine */ 143121310Ssos if (request->device->channel->dma->start(request->device->channel)) { 144120881Ssos ata_prtdev(request->device, "error starting DMA\n"); 145119404Ssos request->result = EIO; 146120881Ssos break; 147119404Ssos } 148124403Ssos 149119404Ssos /* return and wait for interrupt */ 150119404Ssos return ATA_OP_CONTINUES; 151119404Ssos 152119404Ssos /* ATAPI PIO commands */ 153119404Ssos case ATA_R_ATAPI: 154119404Ssos /* is this just a POLL DSC command ? */ 155119404Ssos if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { 156119404Ssos ATA_IDX_OUTB(request->device->channel, ATA_DRIVE, 157119404Ssos ATA_D_IBM | request->device->unit); 158119404Ssos DELAY(10); 159119404Ssos if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC)) 160119404Ssos request->result = EBUSY; 161120881Ssos break; 162119404Ssos } 163119404Ssos 164119404Ssos /* start ATAPI operation */ 165119404Ssos if (ata_command(request->device, ATA_PACKET_CMD, 166119404Ssos request->transfersize << 8, 0, 0)) { 167119404Ssos ata_prtdev(request->device, "error issuing ATA PACKET command\n"); 168119404Ssos request->result = EIO; 169120881Ssos break; 170119404Ssos } 171119404Ssos 172119404Ssos /* command interrupt device ? just return and wait for interrupt */ 173119404Ssos if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR) 174119404Ssos return ATA_OP_CONTINUES; 175119404Ssos 176119404Ssos /* wait for ready to write ATAPI command block */ 177119404Ssos { 178119404Ssos int timeout = 5000; /* might be less for fast devices */ 179119404Ssos while (timeout--) { 180119404Ssos int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON); 181119404Ssos int status = ATA_IDX_INB(request->device->channel, ATA_STATUS); 182119404Ssos 183119404Ssos if (((reason & (ATA_I_CMD | ATA_I_IN)) | 184119404Ssos (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) 185119404Ssos break; 186119404Ssos DELAY(20); 187119404Ssos } 188119404Ssos if (timeout <= 0) { 189119404Ssos ata_prtdev(request->device, 190119404Ssos "timeout waiting for ATAPI ready\n"); 191119404Ssos request->result = EIO; 192120881Ssos break; 193119404Ssos } 194119404Ssos } 195119404Ssos 196119404Ssos /* this seems to be needed for some (slow) devices */ 197119404Ssos DELAY(10); 198119404Ssos 199119404Ssos /* output actual command block */ 200119404Ssos ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA, 201119404Ssos (int16_t *)request->u.atapi.ccb, 202119404Ssos (request->device->param->config & ATA_PROTO_MASK) == 203119404Ssos ATA_PROTO_ATAPI_12 ? 6 : 8); 204119404Ssos 205119404Ssos /* return and wait for interrupt */ 206119404Ssos return ATA_OP_CONTINUES; 207119404Ssos 208119404Ssos case ATA_R_ATAPI|ATA_R_DMA: 209119404Ssos /* is this just a POLL DSC command ? */ 210119404Ssos if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { 211119404Ssos ATA_IDX_OUTB(request->device->channel, ATA_DRIVE, 212119404Ssos ATA_D_IBM | request->device->unit); 213119404Ssos DELAY(10); 214119404Ssos if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC)) 215119404Ssos request->result = EBUSY; 216120881Ssos break; 217119404Ssos } 218119404Ssos 219121310Ssos /* check sanity, setup SG list and DMA engine */ 220121310Ssos if (request->device->channel->dma->load(request->device, 221121310Ssos request->data, 222121310Ssos request->bytecount, 223121310Ssos request->flags & ATA_R_READ)) { 224119404Ssos ata_prtdev(request->device, "setting up DMA failed\n"); 225119404Ssos request->result = EIO; 226120881Ssos break; 227119404Ssos } 228119404Ssos 229119404Ssos /* start ATAPI operation */ 230119404Ssos if (ata_command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) { 231119404Ssos ata_prtdev(request->device, "error issuing ATAPI packet command\n"); 232119404Ssos request->result = EIO; 233120881Ssos break; 234119404Ssos } 235119404Ssos 236119404Ssos /* wait for ready to write ATAPI command block */ 237119404Ssos { 238119404Ssos int timeout = 5000; /* might be less for fast devices */ 239119404Ssos while (timeout--) { 240119404Ssos int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON); 241119404Ssos int status = ATA_IDX_INB(request->device->channel, ATA_STATUS); 242119404Ssos 243119404Ssos if (((reason & (ATA_I_CMD | ATA_I_IN)) | 244119404Ssos (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) 245119404Ssos break; 246119404Ssos DELAY(20); 247119404Ssos } 248119404Ssos if (timeout <= 0) { 249120881Ssos ata_prtdev(request->device,"timeout waiting for ATAPI ready\n"); 250119404Ssos request->result = EIO; 251120881Ssos break; 252119404Ssos } 253119404Ssos } 254119404Ssos 255119404Ssos /* this seems to be needed for some (slow) devices */ 256119404Ssos DELAY(10); 257119404Ssos 258119404Ssos /* output actual command block */ 259119404Ssos ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA, 260119404Ssos (int16_t *)request->u.atapi.ccb, 261119404Ssos (request->device->param->config & ATA_PROTO_MASK) == 262119404Ssos ATA_PROTO_ATAPI_12 ? 6 : 8); 263119404Ssos 264119404Ssos /* start DMA engine */ 265121310Ssos if (request->device->channel->dma->start(request->device->channel)) { 266119404Ssos request->result = EIO; 267120881Ssos break; 268119404Ssos } 269119404Ssos 270119404Ssos /* return and wait for interrupt */ 271119404Ssos return ATA_OP_CONTINUES; 272119404Ssos } 273120881Ssos 274120881Ssos /* request finish here */ 275121311Ssos if (request->device->channel->dma->flags & ATA_DMA_ACTIVE) 276121311Ssos request->device->channel->dma->unload(request->device->channel); 277120881Ssos request->device->channel->running = NULL; 278120881Ssos return ATA_OP_FINISHED; 279119404Ssos} 280119404Ssos 281119404Ssosstatic void 282119404Ssosata_interrupt(void *data) 283119404Ssos{ 284119404Ssos struct ata_channel *ch = (struct ata_channel *)data; 285119404Ssos struct ata_request *request = ch->running; 286119404Ssos int length; 287119404Ssos 288120128Ssos /* ignore this interrupt if there is no running request */ 289120128Ssos if (!request) { 290120128Ssos if (ATA_LOCK_CH(ch, ATA_CONTROL)) { 291120128Ssos u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS); 292120128Ssos u_int8_t error = ATA_IDX_INB(ch, ATA_ERROR); 293120128Ssos 294120128Ssos if (bootverbose) 295120128Ssos ata_printf(ch, -1, 296120128Ssos "spurious interrupt - status=0x%02x error=0x%02x\n", 297120128Ssos status, error); 298120128Ssos ATA_UNLOCK_CH(ch); 299120128Ssos } 300120128Ssos else { 301120128Ssos if (bootverbose) 302120128Ssos ata_printf(ch, -1, "spurious interrupt - channel busy\n"); 303120128Ssos } 304119878Ssos return; 305120128Ssos } 306119878Ssos 307124403Ssos ATA_DEBUG_RQ(request, "interrupt"); 308124403Ssos 309120128Ssos /* ignore interrupt if device is busy */ 310124403Ssos if (!(request->flags & ATA_R_TIMEOUT) && 311124403Ssos ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { 312119878Ssos DELAY(100); 313119878Ssos if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ)) 314119878Ssos return; 315119878Ssos } 316119878Ssos 317124403Ssos ATA_DEBUG_RQ(request, "interrupt accepted"); 318124403Ssos 319119878Ssos /* clear interrupt and get status */ 320120128Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 321119878Ssos 322124403Ssos request->flags |= ATA_R_INTR_SEEN; 323124403Ssos 324121910Ssos switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_CONTROL)) { 325119404Ssos 326119404Ssos /* ATA PIO data transfer and control commands */ 327119404Ssos default: 328119404Ssos 329121910Ssos /* on control commands read back registers to the request struct */ 330121910Ssos if (request->flags & ATA_R_CONTROL) { 331121910Ssos request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT); 332121910Ssos request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) | 333121910Ssos (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) | 334121910Ssos (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16); 335121910Ssos } 336121910Ssos 337119404Ssos /* if we got an error we are done with the HW */ 338119404Ssos if (request->status & ATA_S_ERROR) { 339119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 340119404Ssos break; 341119404Ssos } 342119404Ssos 343121910Ssos /* are we moving data ? */ 344121910Ssos if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { 345119404Ssos 346121910Ssos /* if read data get it */ 347121910Ssos if (request->flags & ATA_R_READ) 348121910Ssos ata_pio_read(request, request->transfersize); 349119404Ssos 350121910Ssos /* update how far we've gotten */ 351121910Ssos request->donecount += request->transfersize; 352119404Ssos 353121910Ssos /* do we need a scoop more ? */ 354121910Ssos if (request->bytecount > request->donecount) { 355119404Ssos 356121910Ssos /* set this transfer size according to HW capabilities */ 357121910Ssos request->transfersize = 358121910Ssos min((request->bytecount - request->donecount), 359121910Ssos request->transfersize); 360120204Ssos 361121910Ssos /* if data write command, output the data */ 362121910Ssos if (request->flags & ATA_R_WRITE) { 363121910Ssos 364121910Ssos /* if we get an error here we are done with the HW */ 365121910Ssos if (ata_wait(request->device, 366121910Ssos (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { 367121910Ssos ata_prtdev(request->device, 368121910Ssos "timeout waiting for write DRQ"); 369121910Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 370121910Ssos break; 371121910Ssos } 372121910Ssos 373121910Ssos /* output data and return waiting for new interrupt */ 374121910Ssos ata_pio_write(request, request->transfersize); 375121910Ssos return; 376119404Ssos } 377120204Ssos 378121910Ssos /* if data read command, return & wait for interrupt */ 379121910Ssos if (request->flags & ATA_R_READ) 380121910Ssos return; 381119404Ssos } 382119404Ssos } 383119404Ssos /* done with HW */ 384119404Ssos break; 385119404Ssos 386119404Ssos /* ATA DMA data transfer commands */ 387119404Ssos case ATA_R_DMA: 388119404Ssos /* stop DMA engine and get status */ 389119404Ssos request->dmastat = ch->dma->stop(ch); 390119404Ssos 391119404Ssos /* did we get error or data */ 392119404Ssos if (request->status & ATA_S_ERROR) 393119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 394119404Ssos else if (request->dmastat & ATA_BMSTAT_ERROR) 395119404Ssos request->status |= ATA_S_ERROR; 396119404Ssos else 397119404Ssos request->donecount = request->bytecount; 398119404Ssos 399121310Ssos /* release SG list etc */ 400121310Ssos ch->dma->unload(ch); 401121310Ssos 402119404Ssos /* done with HW */ 403119404Ssos break; 404119404Ssos 405119404Ssos /* ATAPI PIO commands */ 406119404Ssos case ATA_R_ATAPI: 407119404Ssos length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); 408119404Ssos 409119404Ssos switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) | 410119404Ssos (request->status & ATA_S_DRQ)) { 411119404Ssos 412119404Ssos case ATAPI_P_CMDOUT: 413119404Ssos /* this seems to be needed for some (slow) devices */ 414119404Ssos DELAY(10); 415119404Ssos 416119404Ssos if (!(request->status & ATA_S_DRQ)) { 417119404Ssos ata_prtdev(request->device, "command interrupt without DRQ\n"); 418119404Ssos request->status = ATA_S_ERROR; 419119404Ssos break; 420119404Ssos } 421119404Ssos ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, 422119404Ssos (request->device->param->config & 423119404Ssos ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8); 424119404Ssos /* return wait for interrupt */ 425119404Ssos return; 426119404Ssos 427119404Ssos case ATAPI_P_WRITE: 428119404Ssos if (request->flags & ATA_R_READ) { 429119404Ssos request->status = ATA_S_ERROR; 430119404Ssos ata_prtdev(request->device, 431119404Ssos "%s trying to write on read buffer\n", 432119404Ssos ata_cmd2str(request)); 433119404Ssos break; 434119404Ssos } 435119404Ssos ata_pio_write(request, length); 436119404Ssos request->donecount += length; 437119404Ssos 438119404Ssos /* set next transfer size according to HW capabilities */ 439119404Ssos request->transfersize = min((request->bytecount-request->donecount), 440119404Ssos request->transfersize); 441119404Ssos /* return wait for interrupt */ 442119404Ssos return; 443119404Ssos 444119404Ssos case ATAPI_P_READ: 445119404Ssos if (request->flags & ATA_R_WRITE) { 446119404Ssos request->status = ATA_S_ERROR; 447119404Ssos ata_prtdev(request->device, 448119404Ssos "%s trying to read on write buffer\n", 449119404Ssos ata_cmd2str(request)); 450119404Ssos break; 451119404Ssos } 452119404Ssos ata_pio_read(request, length); 453119404Ssos request->donecount += length; 454119404Ssos 455119404Ssos /* set next transfer size according to HW capabilities */ 456119404Ssos request->transfersize = min((request->bytecount-request->donecount), 457119404Ssos request->transfersize); 458119404Ssos /* return wait for interrupt */ 459119404Ssos return; 460119404Ssos 461119404Ssos case ATAPI_P_DONEDRQ: 462119404Ssos ata_prtdev(request->device, 463119404Ssos "WARNING - %s DONEDRQ non conformant device\n", 464119404Ssos ata_cmd2str(request)); 465119404Ssos if (request->flags & ATA_R_READ) { 466119404Ssos ata_pio_read(request, length); 467119404Ssos request->donecount += length; 468119404Ssos } 469119404Ssos else if (request->flags & ATA_R_WRITE) { 470119404Ssos ata_pio_write(request, length); 471119404Ssos request->donecount += length; 472119404Ssos } 473119404Ssos else 474119404Ssos request->status = ATA_S_ERROR; 475119404Ssos /* FALLTHROUGH */ 476119404Ssos 477119404Ssos case ATAPI_P_ABORT: 478119404Ssos case ATAPI_P_DONE: 479119404Ssos if (request->status & (ATA_S_ERROR | ATA_S_DWF)) 480119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 481119404Ssos break; 482119404Ssos 483119404Ssos default: 484119404Ssos ata_prtdev(request->device, "unknown transfer phase\n"); 485119404Ssos request->status = ATA_S_ERROR; 486119404Ssos } 487121310Ssos 488119404Ssos /* done with HW */ 489119404Ssos break; 490119404Ssos 491119404Ssos /* ATAPI DMA commands */ 492119404Ssos case ATA_R_ATAPI|ATA_R_DMA: 493119404Ssos 494119404Ssos /* stop the engine and get engine status */ 495119404Ssos request->dmastat = ch->dma->stop(ch); 496119404Ssos 497119404Ssos /* did we get error or data */ 498119404Ssos if (request->status & (ATA_S_ERROR | ATA_S_DWF)) 499119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 500119404Ssos else if (request->dmastat & ATA_BMSTAT_ERROR) 501119404Ssos request->status |= ATA_S_ERROR; 502119404Ssos else 503119404Ssos request->donecount = request->bytecount; 504121310Ssos 505121310Ssos /* release SG list etc */ 506121310Ssos ch->dma->unload(ch); 507119404Ssos 508119404Ssos /* done with HW */ 509119404Ssos break; 510119404Ssos } 511119404Ssos 512124403Ssos /* if we timed out, we hold on to the channel, ata_reinit() will unlock */ 513124403Ssos if (request->flags & ATA_R_TIMEOUT) { 514124403Ssos ata_finish(request); 515124403Ssos return; 516124403Ssos } 517124403Ssos 518124403Ssos /* schedule completition for this request */ 519119404Ssos ata_finish(request); 520119404Ssos 521121310Ssos /* unlock the ATA channel for new work */ 522119404Ssos ch->running = NULL; 523119404Ssos ATA_UNLOCK_CH(ch); 524119404Ssos ch->locking(ch, ATA_LF_UNLOCK); 525119404Ssos} 526119404Ssos 527119404Ssos/* must be called with ATA channel locked */ 528119404Ssosstatic void 529119404Ssosata_reset(struct ata_channel *ch) 530119404Ssos{ 531119651Ssos u_int8_t err, lsb, msb, ostat0, ostat1; 532119404Ssos u_int8_t stat0 = 0, stat1 = 0; 533119404Ssos int mask = 0, timeout; 534119404Ssos 535119404Ssos /* do we have any signs of ATA/ATAPI HW being present ? */ 536119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 537119404Ssos DELAY(10); 538119404Ssos ostat0 = ATA_IDX_INB(ch, ATA_STATUS); 539119404Ssos if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { 540119404Ssos stat0 = ATA_S_BUSY; 541119404Ssos mask |= 0x01; 542119404Ssos } 543119404Ssos 544119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); 545119404Ssos DELAY(10); 546119404Ssos ostat1 = ATA_IDX_INB(ch, ATA_STATUS); 547119651Ssos 548119404Ssos /* in some setups we dont want to test for a slave */ 549119404Ssos if (!(ch->flags & ATA_NO_SLAVE)) { 550119404Ssos if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { 551119404Ssos stat1 = ATA_S_BUSY; 552119404Ssos mask |= 0x02; 553119404Ssos } 554119404Ssos } 555119404Ssos 556124403Ssos /* if nothing showed up there is no need to get any further */ 557119404Ssos /* SOS is that too strong?, we just might loose devices here XXX */ 558119404Ssos ch->devices = 0; 559119404Ssos if (!mask) 560119404Ssos return; 561119404Ssos 562119404Ssos if (bootverbose) 563119651Ssos ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", 564119404Ssos mask, ostat0, ostat1); 565119404Ssos 566124403Ssos /* reset host end of channel (if supported) */ 567124403Ssos if (ch->reset) 568124403Ssos ch->reset(ch); 569124403Ssos 570124403Ssos /* reset (both) devices on this channel */ 571119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 572119404Ssos DELAY(10); 573119404Ssos ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); 574119404Ssos DELAY(10000); 575119404Ssos ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS); 576121277Ssos DELAY(100000); 577121277Ssos ATA_IDX_INB(ch, ATA_ERROR); 578119404Ssos 579119404Ssos /* wait for BUSY to go inactive */ 580119501Ssos for (timeout = 0; timeout < 310; timeout++) { 581119404Ssos if (stat0 & ATA_S_BUSY) { 582119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); 583119404Ssos DELAY(10); 584119651Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 585119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 586119651Ssos msb = ATA_IDX_INB(ch, ATA_CYL_MSB); 587119404Ssos stat0 = ATA_IDX_INB(ch, ATA_STATUS); 588119651Ssos if (bootverbose) 589119651Ssos ata_printf(ch, ATA_MASTER, 590119651Ssos "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", 591119651Ssos stat0, err, lsb, msb); 592119953Ssos if (!(stat0 & ATA_S_BUSY)) { 593120279Ssos if ((err & 0x7f) == ATA_E_ILI) { 594120127Ssos if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { 595120127Ssos ch->devices |= ATA_ATAPI_MASTER; 596120127Ssos } 597120127Ssos else if (stat0 & ATA_S_READY) { 598119953Ssos ch->devices |= ATA_ATA_MASTER; 599119953Ssos } 600119651Ssos } 601120203Ssos else if ((stat0 & 0x4f) && err == lsb && err == msb) { 602120203Ssos stat0 |= ATA_S_BUSY; 603120127Ssos } 604119404Ssos } 605119404Ssos } 606123127Ssos if (!((mask == 0x03) && (stat0 & ATA_S_BUSY)) && (stat1 & ATA_S_BUSY)) { 607119404Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); 608119404Ssos DELAY(10); 609119651Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 610119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 611119651Ssos msb = ATA_IDX_INB(ch, ATA_CYL_MSB); 612119404Ssos stat1 = ATA_IDX_INB(ch, ATA_STATUS); 613119651Ssos if (bootverbose) 614119651Ssos ata_printf(ch, ATA_SLAVE, 615119953Ssos " stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", 616119953Ssos stat1, err, lsb, msb); 617119953Ssos if (!(stat1 & ATA_S_BUSY)) { 618120279Ssos if ((err & 0x7f) == ATA_E_ILI) { 619120127Ssos if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { 620120127Ssos ch->devices |= ATA_ATAPI_SLAVE; 621120127Ssos } 622120127Ssos else if (stat1 & ATA_S_READY) { 623119953Ssos ch->devices |= ATA_ATA_SLAVE; 624119953Ssos } 625119651Ssos } 626120203Ssos else if ((stat1 & 0x4f) && err == lsb && err == msb) { 627120203Ssos stat1 |= ATA_S_BUSY; 628120127Ssos } 629119404Ssos } 630119404Ssos } 631119953Ssos if (mask == 0x01) /* wait for master only */ 632119523Ssos if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20)) 633119404Ssos break; 634119953Ssos if (mask == 0x02) /* wait for slave only */ 635119523Ssos if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20)) 636119404Ssos break; 637123421Ssos if (mask == 0x03) { /* wait for both master & slave */ 638123421Ssos if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) 639119404Ssos break; 640123421Ssos if (stat0 == 0xff && timeout > 20) 641123421Ssos mask &= ~0x01; 642123421Ssos if (stat1 == 0xff && timeout > 20) 643123421Ssos mask &= ~0x02; 644123421Ssos } 645119501Ssos DELAY(100000); 646119404Ssos } 647119404Ssos 648124403Ssos /* enable interrupt */ 649124403Ssos DELAY(10); 650124403Ssos ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT); 651124403Ssos 652119404Ssos if (stat0 & ATA_S_BUSY) 653119404Ssos mask &= ~0x01; 654119404Ssos if (stat1 & ATA_S_BUSY) 655119404Ssos mask &= ~0x02; 656119651Ssos 657119404Ssos if (bootverbose) 658119651Ssos ata_printf(ch, -1, 659119651Ssos "reset tp2 mask=%02x stat0=%02x stat1=%02x devices=0x%b\n", 660119651Ssos mask, stat0, stat1, ch->devices, 661119651Ssos "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); 662119404Ssos} 663119404Ssos 664119404Ssosstatic int 665119404Ssosata_wait(struct ata_device *atadev, u_int8_t mask) 666119404Ssos{ 667120628Ssos u_int8_t status; 668119404Ssos int timeout = 0; 669119404Ssos 670119404Ssos DELAY(1); 671120628Ssos 672120628Ssos /* wait 5 seconds for device to get !BUSY */ 673120628Ssos while (timeout < 5000000) { 674119404Ssos status = ATA_IDX_INB(atadev->channel, ATA_STATUS); 675119404Ssos 676119404Ssos /* if drive fails status, reselect the drive just to be sure */ 677119404Ssos if (status == 0xff) { 678119404Ssos ata_prtdev(atadev, "WARNING no status, reselecting device\n"); 679119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); 680119404Ssos DELAY(10); 681119404Ssos status = ATA_IDX_INB(atadev->channel, ATA_STATUS); 682119404Ssos if (status == 0xff) 683119404Ssos return -1; 684119404Ssos } 685119404Ssos 686119404Ssos /* are we done ? */ 687119404Ssos if (!(status & ATA_S_BUSY)) 688119404Ssos break; 689119404Ssos 690119404Ssos if (timeout > 1000) { 691119404Ssos timeout += 1000; 692119404Ssos DELAY(1000); 693119404Ssos } 694119404Ssos else { 695119404Ssos timeout += 10; 696119404Ssos DELAY(10); 697119404Ssos } 698119404Ssos } 699119404Ssos if (timeout >= 5000000) 700119404Ssos return -1; 701119404Ssos if (!mask) 702119404Ssos return (status & ATA_S_ERROR); 703120628Ssos 704120628Ssos DELAY(1); 705119404Ssos 706120628Ssos /* wait 50 msec for bits wanted */ 707119404Ssos timeout = 5000; 708119404Ssos while (timeout--) { 709119404Ssos status = ATA_IDX_INB(atadev->channel, ATA_STATUS); 710119404Ssos if ((status & mask) == mask) 711119404Ssos return (status & ATA_S_ERROR); 712119404Ssos DELAY (10); 713119404Ssos } 714119404Ssos return -1; 715119404Ssos} 716119404Ssos 717119404Ssosstatic int 718119404Ssosata_command(struct ata_device *atadev, u_int8_t command, 719119404Ssos u_int64_t lba, u_int16_t count, u_int16_t feature) 720119404Ssos{ 721119404Ssos if (atadebug) 722119404Ssos ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, " 723119404Ssos "lba=%jd, count=%d, feature=%d\n", 724119404Ssos rman_get_start(atadev->channel->r_io[ATA_DATA].res), 725119404Ssos command, (intmax_t)lba, count, feature); 726119404Ssos 727119404Ssos /* select device */ 728119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); 729119404Ssos 730119404Ssos /* ready to issue command ? */ 731119404Ssos if (ata_wait(atadev, 0) < 0) { 732119404Ssos ata_prtdev(atadev, "timeout sending command=%02x\n", command); 733119404Ssos return -1; 734119404Ssos } 735119404Ssos 736119404Ssos /* only use 48bit addressing if needed (avoid bugs and overhead) */ 737119404Ssos if ((lba > 268435455 || count > 256) && atadev->param && 738119404Ssos atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) { 739119404Ssos 740119404Ssos /* translate command into 48bit version */ 741119404Ssos switch (command) { 742119404Ssos case ATA_READ: 743119404Ssos command = ATA_READ48; break; 744119404Ssos case ATA_READ_MUL: 745119404Ssos command = ATA_READ_MUL48; break; 746119404Ssos case ATA_READ_DMA: 747119404Ssos command = ATA_READ_DMA48; break; 748119404Ssos case ATA_READ_DMA_QUEUED: 749119404Ssos command = ATA_READ_DMA_QUEUED48; break; 750119404Ssos case ATA_WRITE: 751119404Ssos command = ATA_WRITE48; break; 752119404Ssos case ATA_WRITE_MUL: 753119404Ssos command = ATA_WRITE_MUL48; break; 754119404Ssos case ATA_WRITE_DMA: 755119404Ssos command = ATA_WRITE_DMA48; break; 756119404Ssos case ATA_WRITE_DMA_QUEUED: 757119404Ssos command = ATA_WRITE_DMA_QUEUED48; break; 758119404Ssos case ATA_FLUSHCACHE: 759119404Ssos command = ATA_FLUSHCACHE48; break; 760119404Ssos default: 761119404Ssos ata_prtdev(atadev, "can't translate cmd to 48bit version\n"); 762119404Ssos return -1; 763119404Ssos } 764119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff); 765119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff); 766119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff); 767119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff); 768119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff); 769119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); 770119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff); 771119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); 772119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff); 773119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); 774119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit); 775119404Ssos atadev->channel->flags |= ATA_48BIT_ACTIVE; 776119404Ssos } 777119404Ssos else { 778119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature); 779119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count); 780119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); 781119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); 782119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); 783119404Ssos if (atadev->flags & ATA_D_USE_CHS) 784119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, 785119404Ssos ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf)); 786119404Ssos else 787119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, 788119404Ssos ATA_D_IBM | ATA_D_LBA | atadev->unit|((lba>>24)&0xf)); 789119404Ssos atadev->channel->flags &= ~ATA_48BIT_ACTIVE; 790119404Ssos } 791119404Ssos 792119404Ssos /* issue command to controller */ 793119404Ssos ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); 794119404Ssos 795119404Ssos return 0; 796119404Ssos} 797119404Ssos 798119404Ssosstatic void 799119404Ssosata_pio_read(struct ata_request *request, int length) 800119404Ssos{ 801119404Ssos int size = min(request->transfersize, length); 802119404Ssos struct ata_channel *ch = request->device->channel; 803119404Ssos int resid; 804119404Ssos 805119404Ssos if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) 806119404Ssos ATA_IDX_INSW_STRM(ch, ATA_DATA, 807119404Ssos (void*)((uintptr_t)request->data+request->donecount), 808119404Ssos size / sizeof(int16_t)); 809119404Ssos else 810119404Ssos ATA_IDX_INSL_STRM(ch, ATA_DATA, 811119404Ssos (void*)((uintptr_t)request->data+request->donecount), 812119404Ssos size / sizeof(int32_t)); 813119404Ssos 814119404Ssos if (request->transfersize < length) { 815119523Ssos ata_prtdev(request->device, "WARNING - %s read data overrun %d>%d\n", 816119404Ssos ata_cmd2str(request), length, request->transfersize); 817119404Ssos for (resid = request->transfersize; resid < length; 818119404Ssos resid += sizeof(int16_t)) 819119404Ssos ATA_IDX_INW(ch, ATA_DATA); 820119404Ssos } 821119404Ssos} 822119404Ssos 823119404Ssosstatic void 824119404Ssosata_pio_write(struct ata_request *request, int length) 825119404Ssos{ 826119404Ssos int size = min(request->transfersize, length); 827119404Ssos struct ata_channel *ch = request->device->channel; 828119404Ssos int resid; 829119404Ssos 830119404Ssos if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) 831119404Ssos ATA_IDX_OUTSW_STRM(ch, ATA_DATA, 832119404Ssos (void*)((uintptr_t)request->data+request->donecount), 833119404Ssos size / sizeof(int16_t)); 834119404Ssos else 835119404Ssos ATA_IDX_OUTSL_STRM(ch, ATA_DATA, 836119404Ssos (void*)((uintptr_t)request->data+request->donecount), 837119404Ssos size / sizeof(int32_t)); 838119404Ssos 839119404Ssos if (request->transfersize < length) { 840119523Ssos ata_prtdev(request->device, "WARNING - %s write data underrun %d>%d\n", 841119404Ssos ata_cmd2str(request), length, request->transfersize); 842119404Ssos for (resid = request->transfersize; resid < length; 843119404Ssos resid += sizeof(int16_t)) 844119404Ssos ATA_IDX_OUTW(ch, ATA_DATA, 0); 845119404Ssos } 846119404Ssos} 847