1119404Ssos/*- 2230132Suqs * Copyright (c) 1998 - 2008 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 * 15119404Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16119404Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17119404Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18119404Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19119404Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20119404Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21119404Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22119404Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23119404Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24119404Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25119404Ssos */ 26119404Ssos 27119418Sobrien#include <sys/cdefs.h> 28119418Sobrien__FBSDID("$FreeBSD$"); 29119418Sobrien 30119404Ssos#include <sys/param.h> 31119404Ssos#include <sys/systm.h> 32144330Ssos#include <sys/kernel.h> 33144330Ssos#include <sys/endian.h> 34119404Ssos#include <sys/ata.h> 35119404Ssos#include <sys/conf.h> 36144330Ssos#include <sys/ctype.h> 37119404Ssos#include <sys/bus.h> 38124403Ssos#include <sys/sema.h> 39119404Ssos#include <sys/taskqueue.h> 40124534Ssos#include <vm/uma.h> 41119404Ssos#include <machine/bus.h> 42119404Ssos#include <sys/rman.h> 43119404Ssos#include <dev/ata/ata-all.h> 44144330Ssos#include <dev/ata/ata-pci.h> 45144330Ssos#include <ata_if.h> 46119404Ssos 47119404Ssos/* prototypes */ 48154507Ssosstatic int ata_generic_status(device_t dev); 49198717Smavstatic int ata_wait(struct ata_channel *ch, int unit, u_int8_t); 50119450Ssosstatic void ata_pio_read(struct ata_request *, int); 51119450Ssosstatic void ata_pio_write(struct ata_request *, int); 52174576Ssosstatic void ata_tf_read(struct ata_request *); 53174576Ssosstatic void ata_tf_write(struct ata_request *); 54119404Ssos 55119404Ssos/* 56119404Ssos * low level ATA functions 57119404Ssos */ 58119404Ssosvoid 59145713Ssosata_generic_hw(device_t dev) 60119404Ssos{ 61145713Ssos struct ata_channel *ch = device_get_softc(dev); 62145713Ssos 63135819Ssos ch->hw.begin_transaction = ata_begin_transaction; 64135819Ssos ch->hw.end_transaction = ata_end_transaction; 65154507Ssos ch->hw.status = ata_generic_status; 66178067Ssos ch->hw.softreset = NULL; 67128183Ssos ch->hw.command = ata_generic_command; 68174576Ssos ch->hw.tf_read = ata_tf_read; 69174576Ssos ch->hw.tf_write = ata_tf_write; 70178067Ssos ch->hw.pm_read = NULL; 71178067Ssos ch->hw.pm_write = NULL; 72119404Ssos} 73119404Ssos 74145354Ssos/* must be called with ATA channel locked and state_mtx held */ 75154507Ssosint 76135819Ssosata_begin_transaction(struct ata_request *request) 77119404Ssos{ 78178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 79153142Ssos int dummy, error; 80128183Ssos 81135819Ssos ATA_DEBUG_RQ(request, "begin transaction"); 82124403Ssos 83119404Ssos /* disable ATAPI DMA writes if HW doesn't support it */ 84200171Smav if ((ch->flags & ATA_NO_ATAPI_DMA) && 85200171Smav (request->flags & ATA_R_ATAPI) == ATA_R_ATAPI) 86200171Smav request->flags &= ~ATA_R_DMA; 87128183Ssos if ((ch->flags & ATA_ATAPI_DMA_RO) && 88120938Ssos ((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) == 89120938Ssos (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE))) 90119404Ssos request->flags &= ~ATA_R_DMA; 91119404Ssos 92119404Ssos switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { 93119404Ssos 94119404Ssos /* ATA PIO data transfer and control commands */ 95119404Ssos default: 96119404Ssos { 97124403Ssos /* record command direction here as our request might be gone later */ 98119404Ssos int write = (request->flags & ATA_R_WRITE); 99119404Ssos 100119404Ssos /* issue command */ 101145818Ssos if (ch->hw.command(request)) { 102198717Smav device_printf(request->parent, "error issuing %s command\n", 103133834Ssos ata_cmd2str(request)); 104119404Ssos request->result = EIO; 105145354Ssos goto begin_finished; 106119404Ssos } 107119404Ssos 108132582Ssos /* device reset doesn't interrupt */ 109144330Ssos if (request->u.ata.command == ATA_DEVICE_RESET) { 110168430Ssos 111132606Ssos int timeout = 1000000; 112132606Ssos do { 113132606Ssos DELAY(10); 114132606Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 115132606Ssos } while (request->status & ATA_S_BUSY && timeout--); 116133184Ssos if (request->status & ATA_S_ERROR) 117132582Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 118242156Smav ch->hw.tf_read(request); 119145354Ssos goto begin_finished; 120132582Ssos } 121132582Ssos 122119404Ssos /* if write command output the data */ 123119404Ssos if (write) { 124198717Smav if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) { 125198717Smav device_printf(request->parent, 126150129Ssos "timeout waiting for write DRQ\n"); 127119404Ssos request->result = EIO; 128145354Ssos goto begin_finished; 129119404Ssos } 130119404Ssos ata_pio_write(request, request->transfersize); 131119404Ssos } 132119404Ssos } 133145354Ssos goto begin_continue; 134119404Ssos 135119404Ssos /* ATA DMA data transfer commands */ 136119404Ssos case ATA_R_DMA: 137121310Ssos /* check sanity, setup SG list and DMA engine */ 138178067Ssos if ((error = ch->dma.load(request, NULL, &dummy))) { 139198717Smav device_printf(request->parent, "setting up DMA failed\n"); 140153142Ssos request->result = error; 141145354Ssos goto begin_finished; 142119404Ssos } 143119404Ssos 144208870Snwhitehorn /* start DMA engine if necessary */ 145208870Snwhitehorn if ((ch->flags & ATA_DMA_BEFORE_CMD) && 146208870Snwhitehorn ch->dma.start && ch->dma.start(request)) { 147208870Snwhitehorn device_printf(request->parent, "error starting DMA\n"); 148208870Snwhitehorn request->result = EIO; 149208870Snwhitehorn goto begin_finished; 150208870Snwhitehorn } 151208870Snwhitehorn 152119404Ssos /* issue command */ 153145818Ssos if (ch->hw.command(request)) { 154198717Smav device_printf(request->parent, "error issuing %s command\n", 155133834Ssos ata_cmd2str(request)); 156119404Ssos request->result = EIO; 157145354Ssos goto begin_finished; 158119404Ssos } 159119404Ssos 160119404Ssos /* start DMA engine */ 161208870Snwhitehorn if (!(ch->flags & ATA_DMA_BEFORE_CMD) && 162208870Snwhitehorn ch->dma.start && ch->dma.start(request)) { 163198717Smav device_printf(request->parent, "error starting DMA\n"); 164119404Ssos request->result = EIO; 165145354Ssos goto begin_finished; 166119404Ssos } 167145354Ssos goto begin_continue; 168119404Ssos 169119404Ssos /* ATAPI PIO commands */ 170119404Ssos case ATA_R_ATAPI: 171119404Ssos /* is this just a POLL DSC command ? */ 172119404Ssos if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { 173198717Smav ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit)); 174119404Ssos DELAY(10); 175144707Ssos if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC)) 176119404Ssos request->result = EBUSY; 177145354Ssos goto begin_finished; 178119404Ssos } 179119404Ssos 180119404Ssos /* start ATAPI operation */ 181145818Ssos if (ch->hw.command(request)) { 182198717Smav device_printf(request->parent, "error issuing ATA PACKET command\n"); 183119404Ssos request->result = EIO; 184145354Ssos goto begin_finished; 185119404Ssos } 186145354Ssos goto begin_continue; 187119404Ssos 188145713Ssos /* ATAPI DMA commands */ 189119404Ssos case ATA_R_ATAPI|ATA_R_DMA: 190119404Ssos /* is this just a POLL DSC command ? */ 191119404Ssos if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { 192198717Smav ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit)); 193119404Ssos DELAY(10); 194144707Ssos if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC)) 195119404Ssos request->result = EBUSY; 196145354Ssos goto begin_finished; 197119404Ssos } 198119404Ssos 199121310Ssos /* check sanity, setup SG list and DMA engine */ 200178067Ssos if ((error = ch->dma.load(request, NULL, &dummy))) { 201198717Smav device_printf(request->parent, "setting up DMA failed\n"); 202153142Ssos request->result = error; 203145354Ssos goto begin_finished; 204119404Ssos } 205119404Ssos 206119404Ssos /* start ATAPI operation */ 207145818Ssos if (ch->hw.command(request)) { 208198717Smav device_printf(request->parent, "error issuing ATA PACKET command\n"); 209119404Ssos request->result = EIO; 210145354Ssos goto begin_finished; 211119404Ssos } 212119404Ssos 213119404Ssos /* start DMA engine */ 214178067Ssos if (ch->dma.start && ch->dma.start(request)) { 215119404Ssos request->result = EIO; 216145354Ssos goto begin_finished; 217119404Ssos } 218145354Ssos goto begin_continue; 219119404Ssos } 220145354Ssos /* NOT REACHED */ 221145354Ssos printf("ata_begin_transaction OOPS!!!\n"); 222120881Ssos 223145354Ssosbegin_finished: 224178856Sgrehan if (ch->dma.unload) { 225178856Sgrehan ch->dma.unload(request); 226178856Sgrehan } 227120881Ssos return ATA_OP_FINISHED; 228145354Ssos 229145354Ssosbegin_continue: 230145354Ssos callout_reset(&request->callout, request->timeout * hz, 231145354Ssos (timeout_t*)ata_timeout, request); 232145354Ssos return ATA_OP_CONTINUES; 233119404Ssos} 234119404Ssos 235145354Ssos/* must be called with ATA channel locked and state_mtx held */ 236154507Ssosint 237135819Ssosata_end_transaction(struct ata_request *request) 238119404Ssos{ 239178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 240119404Ssos int length; 241119404Ssos 242135819Ssos ATA_DEBUG_RQ(request, "end transaction"); 243119878Ssos 244119878Ssos /* clear interrupt and get status */ 245120128Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 246119878Ssos 247121910Ssos switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_CONTROL)) { 248119404Ssos 249119404Ssos /* ATA PIO data transfer and control commands */ 250119404Ssos default: 251144330Ssos 252144330Ssos /* on timeouts we have no data or anything so just return */ 253142974Smdodd if (request->flags & ATA_R_TIMEOUT) 254145354Ssos goto end_finished; 255119404Ssos 256242156Smav /* Read back registers to the request struct. */ 257242156Smav if ((request->status & ATA_S_ERROR) || 258242156Smav (request->flags & (ATA_R_CONTROL | ATA_R_NEEDRESULT))) { 259174576Ssos ch->hw.tf_read(request); 260121910Ssos } 261121910Ssos 262119404Ssos /* if we got an error we are done with the HW */ 263119404Ssos if (request->status & ATA_S_ERROR) { 264119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 265145354Ssos goto end_finished; 266119404Ssos } 267119404Ssos 268121910Ssos /* are we moving data ? */ 269121910Ssos if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { 270119404Ssos 271121910Ssos /* if read data get it */ 272144330Ssos if (request->flags & ATA_R_READ) { 273150311Ssos int flags = ATA_S_DRQ; 274150311Ssos 275150311Ssos if (request->u.ata.command != ATA_ATAPI_IDENTIFY) 276150311Ssos flags |= ATA_S_READY; 277198717Smav if (ata_wait(ch, request->unit, flags) < 0) { 278198717Smav device_printf(request->parent, 279150129Ssos "timeout waiting for read DRQ\n"); 280144330Ssos request->result = EIO; 281145354Ssos goto end_finished; 282144330Ssos } 283121910Ssos ata_pio_read(request, request->transfersize); 284144330Ssos } 285119404Ssos 286121910Ssos /* update how far we've gotten */ 287143172Snjl request->donecount += request->transfersize; 288119404Ssos 289121910Ssos /* do we need a scoop more ? */ 290121910Ssos if (request->bytecount > request->donecount) { 291119404Ssos 292121910Ssos /* set this transfer size according to HW capabilities */ 293121910Ssos request->transfersize = 294121910Ssos min((request->bytecount - request->donecount), 295121910Ssos request->transfersize); 296120204Ssos 297121910Ssos /* if data write command, output the data */ 298121910Ssos if (request->flags & ATA_R_WRITE) { 299121910Ssos 300121910Ssos /* if we get an error here we are done with the HW */ 301198717Smav if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) { 302198717Smav device_printf(request->parent, 303150129Ssos "timeout waiting for write DRQ\n"); 304121910Ssos request->status = ATA_IDX_INB(ch, ATA_STATUS); 305145354Ssos goto end_finished; 306121910Ssos } 307121910Ssos 308121910Ssos /* output data and return waiting for new interrupt */ 309121910Ssos ata_pio_write(request, request->transfersize); 310145354Ssos goto end_continue; 311119404Ssos } 312120204Ssos 313121910Ssos /* if data read command, return & wait for interrupt */ 314121910Ssos if (request->flags & ATA_R_READ) 315145354Ssos goto end_continue; 316119404Ssos } 317119404Ssos } 318119404Ssos /* done with HW */ 319145354Ssos goto end_finished; 320119404Ssos 321119404Ssos /* ATA DMA data transfer commands */ 322119404Ssos case ATA_R_DMA: 323128183Ssos 324119404Ssos /* stop DMA engine and get status */ 325178067Ssos if (ch->dma.stop) 326178278Ssos request->dma->status = ch->dma.stop(request); 327119404Ssos 328119404Ssos /* did we get error or data */ 329119404Ssos if (request->status & ATA_S_ERROR) 330119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 331178278Ssos else if (request->dma->status & ATA_BMSTAT_ERROR) 332119404Ssos request->status |= ATA_S_ERROR; 333144330Ssos else if (!(request->flags & ATA_R_TIMEOUT)) 334119404Ssos request->donecount = request->bytecount; 335119404Ssos 336242156Smav /* Read back registers to the request struct. */ 337242156Smav if ((request->status & ATA_S_ERROR) || 338242156Smav (request->flags & (ATA_R_CONTROL | ATA_R_NEEDRESULT))) { 339242156Smav ch->hw.tf_read(request); 340242156Smav } 341242156Smav 342121310Ssos /* release SG list etc */ 343178067Ssos ch->dma.unload(request); 344121310Ssos 345119404Ssos /* done with HW */ 346145354Ssos goto end_finished; 347119404Ssos 348119404Ssos /* ATAPI PIO commands */ 349119404Ssos case ATA_R_ATAPI: 350119404Ssos length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); 351119404Ssos 352144330Ssos /* on timeouts we have no data or anything so just return */ 353144330Ssos if (request->flags & ATA_R_TIMEOUT) 354145354Ssos goto end_finished; 355144330Ssos 356119404Ssos switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) | 357119404Ssos (request->status & ATA_S_DRQ)) { 358119404Ssos 359119404Ssos case ATAPI_P_CMDOUT: 360119404Ssos /* this seems to be needed for some (slow) devices */ 361119404Ssos DELAY(10); 362119404Ssos 363119404Ssos if (!(request->status & ATA_S_DRQ)) { 364198717Smav device_printf(request->parent, "command interrupt without DRQ\n"); 365119404Ssos request->status = ATA_S_ERROR; 366145354Ssos goto end_finished; 367119404Ssos } 368119404Ssos ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, 369198717Smav (request->flags & ATA_R_ATAPI16) ? 8 : 6); 370119404Ssos /* return wait for interrupt */ 371145354Ssos goto end_continue; 372119404Ssos 373119404Ssos case ATAPI_P_WRITE: 374119404Ssos if (request->flags & ATA_R_READ) { 375119404Ssos request->status = ATA_S_ERROR; 376198717Smav device_printf(request->parent, 377144330Ssos "%s trying to write on read buffer\n", 378119404Ssos ata_cmd2str(request)); 379145354Ssos goto end_finished; 380119404Ssos } 381119404Ssos ata_pio_write(request, length); 382119404Ssos request->donecount += length; 383119404Ssos 384119404Ssos /* set next transfer size according to HW capabilities */ 385119404Ssos request->transfersize = min((request->bytecount-request->donecount), 386119404Ssos request->transfersize); 387119404Ssos /* return wait for interrupt */ 388145354Ssos goto end_continue; 389119404Ssos 390119404Ssos case ATAPI_P_READ: 391119404Ssos if (request->flags & ATA_R_WRITE) { 392119404Ssos request->status = ATA_S_ERROR; 393198717Smav device_printf(request->parent, 394144330Ssos "%s trying to read on write buffer\n", 395119404Ssos ata_cmd2str(request)); 396145354Ssos goto end_finished; 397119404Ssos } 398119404Ssos ata_pio_read(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 */ 405145354Ssos goto end_continue; 406119404Ssos 407119404Ssos case ATAPI_P_DONEDRQ: 408198717Smav device_printf(request->parent, 409144330Ssos "WARNING - %s DONEDRQ non conformant device\n", 410144330Ssos ata_cmd2str(request)); 411119404Ssos if (request->flags & ATA_R_READ) { 412119404Ssos ata_pio_read(request, length); 413119404Ssos request->donecount += length; 414119404Ssos } 415119404Ssos else if (request->flags & ATA_R_WRITE) { 416119404Ssos ata_pio_write(request, length); 417119404Ssos request->donecount += length; 418119404Ssos } 419119404Ssos else 420119404Ssos request->status = ATA_S_ERROR; 421119404Ssos /* FALLTHROUGH */ 422119404Ssos 423119404Ssos case ATAPI_P_ABORT: 424119404Ssos case ATAPI_P_DONE: 425119404Ssos if (request->status & (ATA_S_ERROR | ATA_S_DWF)) 426119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 427145354Ssos goto end_finished; 428119404Ssos 429119404Ssos default: 430198717Smav device_printf(request->parent, "unknown transfer phase\n"); 431119404Ssos request->status = ATA_S_ERROR; 432119404Ssos } 433121310Ssos 434119404Ssos /* done with HW */ 435145354Ssos goto end_finished; 436119404Ssos 437119404Ssos /* ATAPI DMA commands */ 438119404Ssos case ATA_R_ATAPI|ATA_R_DMA: 439119404Ssos 440145818Ssos /* stop DMA engine and get status */ 441178067Ssos if (ch->dma.stop) 442178278Ssos request->dma->status = ch->dma.stop(request); 443119404Ssos 444119404Ssos /* did we get error or data */ 445119404Ssos if (request->status & (ATA_S_ERROR | ATA_S_DWF)) 446119404Ssos request->error = ATA_IDX_INB(ch, ATA_ERROR); 447178278Ssos else if (request->dma->status & ATA_BMSTAT_ERROR) 448119404Ssos request->status |= ATA_S_ERROR; 449144330Ssos else if (!(request->flags & ATA_R_TIMEOUT)) 450119404Ssos request->donecount = request->bytecount; 451121310Ssos 452121310Ssos /* release SG list etc */ 453178067Ssos ch->dma.unload(request); 454119404Ssos 455119404Ssos /* done with HW */ 456145354Ssos goto end_finished; 457119404Ssos } 458145354Ssos /* NOT REACHED */ 459145354Ssos printf("ata_end_transaction OOPS!!\n"); 460144330Ssos 461145354Ssosend_finished: 462145354Ssos callout_stop(&request->callout); 463145354Ssos return ATA_OP_FINISHED; 464144330Ssos 465145354Ssosend_continue: 466145354Ssos return ATA_OP_CONTINUES; 467119404Ssos} 468119404Ssos 469154507Ssos/* must be called with ATA channel locked and state_mtx held */ 470145641Ssosvoid 471145713Ssosata_generic_reset(device_t dev) 472119404Ssos{ 473145713Ssos struct ata_channel *ch = device_get_softc(dev); 474145713Ssos 475144330Ssos u_int8_t ostat0 = 0, stat0 = 0, ostat1 = 0, stat1 = 0; 476144330Ssos u_int8_t err = 0, lsb = 0, msb = 0; 477119404Ssos int mask = 0, timeout; 478119404Ssos 479119404Ssos /* do we have any signs of ATA/ATAPI HW being present ? */ 480178203Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER)); 481119404Ssos DELAY(10); 482119404Ssos ostat0 = ATA_IDX_INB(ch, ATA_STATUS); 483212145Smav if (((ostat0 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) && 484212145Smav ostat0 != 0xa5) { 485119404Ssos stat0 = ATA_S_BUSY; 486119404Ssos mask |= 0x01; 487119404Ssos } 488119404Ssos 489119404Ssos /* in some setups we dont want to test for a slave */ 490119404Ssos if (!(ch->flags & ATA_NO_SLAVE)) { 491178203Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE)); 492144330Ssos DELAY(10); 493144330Ssos ostat1 = ATA_IDX_INB(ch, ATA_STATUS); 494212145Smav if (((ostat1 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) && 495212145Smav ostat1 != 0xa5) { 496119404Ssos stat1 = ATA_S_BUSY; 497119404Ssos mask |= 0x02; 498119404Ssos } 499119404Ssos } 500119404Ssos 501128437Ssos if (bootverbose) 502145713Ssos device_printf(dev, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", 503144330Ssos mask, ostat0, ostat1); 504128437Ssos 505124403Ssos /* if nothing showed up there is no need to get any further */ 506250576Seadler /* XXX SOS is that too strong?, we just might lose devices here */ 507119404Ssos ch->devices = 0; 508119404Ssos if (!mask) 509119404Ssos return; 510119404Ssos 511124403Ssos /* reset (both) devices on this channel */ 512178203Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER)); 513119404Ssos DELAY(10); 514144707Ssos ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET); 515134698Ssos ata_udelay(10000); 516144707Ssos ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS); 517134698Ssos ata_udelay(100000); 518121277Ssos ATA_IDX_INB(ch, ATA_ERROR); 519119404Ssos 520119404Ssos /* wait for BUSY to go inactive */ 521119501Ssos for (timeout = 0; timeout < 310; timeout++) { 522144330Ssos if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) { 523178203Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_MASTER)); 524119404Ssos DELAY(10); 525212359Snwhitehorn if (ch->flags & ATA_STATUS_IS_LONG) 526212359Snwhitehorn stat0 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff; 527212359Snwhitehorn else 528212359Snwhitehorn stat0 = ATA_IDX_INB(ch, ATA_STATUS); 529144330Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 530119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 531119651Ssos msb = ATA_IDX_INB(ch, ATA_CYL_MSB); 532119651Ssos if (bootverbose) 533145713Ssos device_printf(dev, 534144330Ssos "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", 535144330Ssos stat0, err, lsb, msb); 536145354Ssos if (stat0 == err && lsb == err && msb == err && 537145354Ssos timeout > (stat0 & ATA_S_BUSY ? 100 : 10)) 538144330Ssos mask &= ~0x01; 539119953Ssos if (!(stat0 & ATA_S_BUSY)) { 540120279Ssos if ((err & 0x7f) == ATA_E_ILI) { 541120127Ssos if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { 542120127Ssos ch->devices |= ATA_ATAPI_MASTER; 543120127Ssos } 544220911Smav else if (lsb == 0 && msb == 0 && (stat0 & ATA_S_READY)) { 545119953Ssos ch->devices |= ATA_ATA_MASTER; 546119953Ssos } 547119651Ssos } 548144330Ssos else if ((stat0 & 0x0f) && err == lsb && err == msb) { 549120203Ssos stat0 |= ATA_S_BUSY; 550120127Ssos } 551119404Ssos } 552119404Ssos } 553144330Ssos 554144591Ssos if ((mask & 0x02) && (stat1 & ATA_S_BUSY) && 555144591Ssos !((mask & 0x01) && (stat0 & ATA_S_BUSY))) { 556178203Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_SLAVE)); 557119404Ssos DELAY(10); 558212359Snwhitehorn if (ch->flags & ATA_STATUS_IS_LONG) 559212359Snwhitehorn stat1 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff; 560212359Snwhitehorn else 561212359Snwhitehorn stat1 = ATA_IDX_INB(ch, ATA_STATUS); 562144330Ssos err = ATA_IDX_INB(ch, ATA_ERROR); 563119651Ssos lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); 564119651Ssos msb = ATA_IDX_INB(ch, ATA_CYL_MSB); 565119651Ssos if (bootverbose) 566145713Ssos device_printf(dev, 567144330Ssos "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", 568144330Ssos stat1, err, lsb, msb); 569145354Ssos if (stat1 == err && lsb == err && msb == err && 570145354Ssos timeout > (stat1 & ATA_S_BUSY ? 100 : 10)) 571144330Ssos mask &= ~0x02; 572119953Ssos if (!(stat1 & ATA_S_BUSY)) { 573120279Ssos if ((err & 0x7f) == ATA_E_ILI) { 574120127Ssos if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { 575120127Ssos ch->devices |= ATA_ATAPI_SLAVE; 576120127Ssos } 577220911Smav else if (lsb == 0 && msb == 0 && (stat1 & ATA_S_READY)) { 578119953Ssos ch->devices |= ATA_ATA_SLAVE; 579119953Ssos } 580119651Ssos } 581144591Ssos else if ((stat1 & 0x0f) && err == lsb && err == msb) { 582144591Ssos stat1 |= ATA_S_BUSY; 583120127Ssos } 584119404Ssos } 585119404Ssos } 586144330Ssos 587212145Smav if ((ch->flags & ATA_KNOWN_PRESENCE) == 0 && 588212145Smav timeout > ((mask == 0x03) ? 20 : 10)) { 589212145Smav if ((mask & 0x01) && stat0 == 0xff) 590212145Smav mask &= ~0x01; 591212145Smav if ((mask & 0x02) && stat1 == 0xff) 592212145Smav mask &= ~0x02; 593212145Smav } 594212145Smav if (((mask & 0x01) == 0 || !(stat0 & ATA_S_BUSY)) && 595212145Smav ((mask & 0x02) == 0 || !(stat1 & ATA_S_BUSY))) 596119404Ssos break; 597134698Ssos ata_udelay(100000); 598142972Smdodd } 599119404Ssos 600119404Ssos if (bootverbose) 601178203Ssos device_printf(dev, "reset tp2 stat0=%02x stat1=%02x devices=0x%x\n", 602178203Ssos stat0, stat1, ch->devices); 603119404Ssos} 604119404Ssos 605154507Ssos/* must be called with ATA channel locked and state_mtx held */ 606249203Smariusstatic int 607154507Ssosata_generic_status(device_t dev) 608154507Ssos{ 609154507Ssos struct ata_channel *ch = device_get_softc(dev); 610154507Ssos 611154507Ssos if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { 612154507Ssos DELAY(100); 613154507Ssos if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) 614154507Ssos return 0; 615154507Ssos } 616154507Ssos return 1; 617154507Ssos} 618154507Ssos 619119404Ssosstatic int 620198717Smavata_wait(struct ata_channel *ch, int unit, u_int8_t mask) 621119404Ssos{ 622120628Ssos u_int8_t status; 623119404Ssos int timeout = 0; 624119404Ssos 625119404Ssos DELAY(1); 626120628Ssos 627144790Ssos /* wait at max 1 second for device to get !BUSY */ 628144790Ssos while (timeout < 1000000) { 629144330Ssos status = ATA_IDX_INB(ch, ATA_ALTSTAT); 630119404Ssos 631144330Ssos /* if drive fails status, reselect the drive and try again */ 632119404Ssos if (status == 0xff) { 633198717Smav ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(unit)); 634144330Ssos timeout += 1000; 635144330Ssos DELAY(1000); 636144330Ssos continue; 637119404Ssos } 638119404Ssos 639119404Ssos /* are we done ? */ 640119404Ssos if (!(status & ATA_S_BUSY)) 641144330Ssos break; 642119404Ssos 643119404Ssos if (timeout > 1000) { 644119404Ssos timeout += 1000; 645119404Ssos DELAY(1000); 646119404Ssos } 647119404Ssos else { 648119404Ssos timeout += 10; 649119404Ssos DELAY(10); 650119404Ssos } 651144330Ssos } 652144790Ssos if (timeout >= 1000000) 653144330Ssos return -2; 654144330Ssos if (!mask) 655144330Ssos return (status & ATA_S_ERROR); 656120628Ssos 657120628Ssos DELAY(1); 658119404Ssos 659144330Ssos /* wait 50 msec for bits wanted */ 660119404Ssos timeout = 5000; 661144330Ssos while (timeout--) { 662144330Ssos status = ATA_IDX_INB(ch, ATA_ALTSTAT); 663119404Ssos if ((status & mask) == mask) 664144330Ssos return (status & ATA_S_ERROR); 665144330Ssos DELAY(10); 666144330Ssos } 667144330Ssos return -3; 668119404Ssos} 669119404Ssos 670128183Ssosint 671145818Ssosata_generic_command(struct ata_request *request) 672119404Ssos{ 673178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 674119404Ssos 675119404Ssos /* select device */ 676198717Smav ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit)); 677119404Ssos 678119404Ssos /* ready to issue command ? */ 679198717Smav if (ata_wait(ch, request->unit, 0) < 0) { 680198717Smav device_printf(request->parent, "timeout waiting to issue command\n"); 681214896Smav request->flags |= ATA_R_TIMEOUT; 682214896Smav return (-1); 683119404Ssos } 684119404Ssos 685125328Ssos /* enable interrupt */ 686144707Ssos ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT); 687125328Ssos 688145818Ssos if (request->flags & ATA_R_ATAPI) { 689146266Ssos int timeout = 5000; 690198717Smav int res; 691119404Ssos 692146266Ssos /* issue packet command to controller */ 693146176Ssos if (request->flags & ATA_R_DMA) { 694146096Ssos ATA_IDX_OUTB(ch, ATA_FEATURE, ATA_F_DMA); 695146176Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0); 696146176Ssos ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0); 697146176Ssos } 698146176Ssos else { 699146176Ssos ATA_IDX_OUTB(ch, ATA_FEATURE, 0); 700146176Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->transfersize); 701146176Ssos ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->transfersize >> 8); 702146176Ssos } 703146096Ssos ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_PACKET_CMD); 704145818Ssos 705145818Ssos /* command interrupt device ? just return and wait for interrupt */ 706198717Smav if (request->flags & ATA_R_ATAPI_INTR) 707214896Smav return (0); 708145818Ssos 709198717Smav /* command processed ? */ 710198717Smav res = ata_wait(ch, request->unit, 0); 711198717Smav if (res != 0) { 712214896Smav if (res < 0) { 713214896Smav device_printf(request->parent, 714214896Smav "timeout waiting for PACKET command\n"); 715214896Smav request->flags |= ATA_R_TIMEOUT; 716214896Smav } 717198717Smav return (-1); 718198717Smav } 719145818Ssos /* wait for ready to write ATAPI command block */ 720146266Ssos while (timeout--) { 721146266Ssos int reason = ATA_IDX_INB(ch, ATA_IREASON); 722146266Ssos int status = ATA_IDX_INB(ch, ATA_STATUS); 723145818Ssos 724146266Ssos if (((reason & (ATA_I_CMD | ATA_I_IN)) | 725146266Ssos (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) 726146266Ssos break; 727146266Ssos DELAY(20); 728146266Ssos } 729146266Ssos if (timeout <= 0) { 730214896Smav device_printf(request->parent, 731214896Smav "timeout waiting for ATAPI ready\n"); 732214896Smav request->flags |= ATA_R_TIMEOUT; 733214896Smav return (-1); 734146266Ssos } 735145818Ssos 736146266Ssos /* this seems to be needed for some (slow) devices */ 737146266Ssos DELAY(10); 738146266Ssos 739146266Ssos /* output command block */ 740146266Ssos ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, 741198717Smav (request->flags & ATA_R_ATAPI16) ? 8 : 6); 742119404Ssos } 743119404Ssos else { 744174576Ssos ch->hw.tf_write(request); 745174576Ssos 746174576Ssos /* issue command to controller */ 747174576Ssos ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command); 748174576Ssos } 749214896Smav return (0); 750174576Ssos} 751174576Ssos 752174576Ssosstatic void 753174576Ssosata_tf_read(struct ata_request *request) 754174576Ssos{ 755178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 756174576Ssos 757198717Smav if (request->flags & ATA_R_48BIT) { 758174576Ssos ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT | ATA_A_HOB); 759174576Ssos request->u.ata.count = (ATA_IDX_INB(ch, ATA_COUNT) << 8); 760174576Ssos request->u.ata.lba = 761174576Ssos ((u_int64_t)(ATA_IDX_INB(ch, ATA_SECTOR)) << 24) | 762174576Ssos ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_LSB)) << 32) | 763174576Ssos ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_MSB)) << 40); 764174576Ssos 765174576Ssos ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT); 766174576Ssos request->u.ata.count |= ATA_IDX_INB(ch, ATA_COUNT); 767174576Ssos request->u.ata.lba |= 768174576Ssos (ATA_IDX_INB(ch, ATA_SECTOR) | 769174576Ssos (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) | 770174576Ssos (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16)); 771174576Ssos } 772174576Ssos else { 773174576Ssos request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT); 774174576Ssos request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) | 775174576Ssos (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) | 776174576Ssos (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) | 777174576Ssos ((ATA_IDX_INB(ch, ATA_DRIVE) & 0xf) << 24); 778174576Ssos } 779174576Ssos} 780174576Ssos 781174576Ssosstatic void 782174576Ssosata_tf_write(struct ata_request *request) 783174576Ssos{ 784178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 785174576Ssos 786198717Smav if (request->flags & ATA_R_48BIT) { 787174576Ssos ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature >> 8); 788174576Ssos ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); 789174576Ssos ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count >> 8); 790174576Ssos ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); 791174576Ssos ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba >> 24); 792174576Ssos ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba); 793174576Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 32); 794174576Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); 795174576Ssos ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 40); 796174576Ssos ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); 797198717Smav ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(request->unit)); 798174576Ssos } 799174576Ssos else { 800174576Ssos ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); 801174576Ssos ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); 802174576Ssos ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba); 803174576Ssos ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); 804174576Ssos ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); 805174576Ssos ATA_IDX_OUTB(ch, ATA_DRIVE, 806198717Smav ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit) | 807174576Ssos ((request->u.ata.lba >> 24) & 0x0f)); 808119404Ssos } 809119404Ssos} 810119404Ssos 811119404Ssosstatic void 812119404Ssosata_pio_read(struct ata_request *request, int length) 813119404Ssos{ 814178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 815238673Smav uint8_t *addr; 816119404Ssos int size = min(request->transfersize, length); 817119404Ssos int resid; 818246257Smarius uint8_t buf[2] __aligned(sizeof(int16_t)); 819246257Smarius#ifndef __NO_STRICT_ALIGNMENT 820246257Smarius int i; 821246257Smarius#endif 822119404Ssos 823238673Smav addr = (uint8_t *)request->data + request->donecount; 824246257Smarius if (__predict_false(ch->flags & ATA_USE_16BIT || 825246257Smarius (size % sizeof(int32_t)) || ((uintptr_t)addr % sizeof(int32_t)))) { 826246257Smarius#ifndef __NO_STRICT_ALIGNMENT 827246257Smarius if (__predict_false((uintptr_t)addr % sizeof(int16_t))) { 828246257Smarius for (i = 0, resid = size & ~1; resid > 0; resid -= 829246257Smarius sizeof(int16_t)) { 830246257Smarius *(uint16_t *)&buf = ATA_IDX_INW_STRM(ch, ATA_DATA); 831246257Smarius addr[i++] = buf[0]; 832246257Smarius addr[i++] = buf[1]; 833246257Smarius } 834246257Smarius } else 835246257Smarius#endif 836246257Smarius ATA_IDX_INSW_STRM(ch, ATA_DATA, (void*)addr, size / 837246257Smarius sizeof(int16_t)); 838214880Smav if (size & 1) { 839246257Smarius *(uint16_t *)&buf = ATA_IDX_INW_STRM(ch, ATA_DATA); 840238673Smav (addr + (size & ~1))[0] = buf[0]; 841214880Smav } 842214880Smav } else 843238673Smav ATA_IDX_INSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t)); 844119404Ssos 845119404Ssos if (request->transfersize < length) { 846198717Smav device_printf(request->parent, "WARNING - %s read data overrun %d>%d\n", 847119404Ssos ata_cmd2str(request), length, request->transfersize); 848214880Smav for (resid = request->transfersize + (size & 1); resid < length; 849119404Ssos resid += sizeof(int16_t)) 850119404Ssos ATA_IDX_INW(ch, ATA_DATA); 851119404Ssos } 852119404Ssos} 853119404Ssos 854119404Ssosstatic void 855119404Ssosata_pio_write(struct ata_request *request, int length) 856119404Ssos{ 857178067Ssos struct ata_channel *ch = device_get_softc(request->parent); 858238673Smav uint8_t *addr; 859119404Ssos int size = min(request->transfersize, length); 860119404Ssos int resid; 861246257Smarius uint8_t buf[2] __aligned(sizeof(int16_t)); 862246257Smarius#ifndef __NO_STRICT_ALIGNMENT 863246257Smarius int i; 864246257Smarius#endif 865119404Ssos 866246257Smarius size = min(request->transfersize, length); 867238673Smav addr = (uint8_t *)request->data + request->donecount; 868246257Smarius if (__predict_false(ch->flags & ATA_USE_16BIT || 869246257Smarius (size % sizeof(int32_t)) || ((uintptr_t)addr % sizeof(int32_t)))) { 870246257Smarius#ifndef __NO_STRICT_ALIGNMENT 871246257Smarius if (__predict_false((uintptr_t)addr % sizeof(int16_t))) { 872246257Smarius for (i = 0, resid = size & ~1; resid > 0; resid -= 873246257Smarius sizeof(int16_t)) { 874246257Smarius buf[0] = addr[i++]; 875246257Smarius buf[1] = addr[i++]; 876246257Smarius ATA_IDX_OUTW_STRM(ch, ATA_DATA, *(uint16_t *)&buf); 877246257Smarius } 878246257Smarius } else 879246257Smarius#endif 880246257Smarius ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void*)addr, size / 881246257Smarius sizeof(int16_t)); 882214880Smav if (size & 1) { 883238673Smav buf[0] = (addr + (size & ~1))[0]; 884246257Smarius ATA_IDX_OUTW_STRM(ch, ATA_DATA, *(uint16_t *)&buf); 885214880Smav } 886214880Smav } else 887238673Smav ATA_IDX_OUTSL_STRM(ch, ATA_DATA, (void*)addr, size / sizeof(int32_t)); 888119404Ssos 889119404Ssos if (request->transfersize < length) { 890198717Smav device_printf(request->parent, "WARNING - %s write data underrun %d>%d\n", 891119404Ssos ata_cmd2str(request), length, request->transfersize); 892214880Smav for (resid = request->transfersize + (size & 1); resid < length; 893119404Ssos resid += sizeof(int16_t)) 894119404Ssos ATA_IDX_OUTW(ch, ATA_DATA, 0); 895119404Ssos } 896119404Ssos} 897