1 /* 2 * Inline routines shareable across OS platforms. 3 * 4 * Copyright (c) 1994-2001 Justin T. Gibbs. 5 * Copyright (c) 2000-2002 Adaptec Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification. 14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 15 * substantially similar to the "NO WARRANTY" disclaimer below 16 * ("Disclaimer") and any redistribution must be conditioned upon 17 * including a substantially similar Disclaimer requirement for further 18 * binary redistribution. 19 * 3. Neither the names of the above-listed copyright holders nor the names 20 * of any contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * Alternatively, this software may be distributed under the terms of the 24 * GNU General Public License ("GPL") version 2 as published by the Free 25 * Software Foundation. 26 * 27 * NO WARRANTY 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 37 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGES. 39 * 40 * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#39 $ 41 * 42 * $FreeBSD$ 43 */ 44 45 #ifndef _AIC79XX_INLINE_H_ 46 #define _AIC79XX_INLINE_H_ 47 48 /******************************** Debugging ***********************************/ 49 static __inline char *ahd_name(struct ahd_softc *ahd); 50 51 static __inline char * 52 ahd_name(struct ahd_softc *ahd) 53 { 54 return (ahd->name); 55 } 56 57 /************************ Sequencer Execution Control *************************/ 58 static __inline void ahd_known_modes(struct ahd_softc *ahd, 59 ahd_mode src, ahd_mode dst); 60 static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, 61 ahd_mode src, 62 ahd_mode dst); 63 static __inline void ahd_extract_mode_state(struct ahd_softc *ahd, 64 ahd_mode_state state, 65 ahd_mode *src, ahd_mode *dst); 66 static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, 67 ahd_mode dst); 68 static __inline void ahd_update_modes(struct ahd_softc *ahd); 69 static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 70 ahd_mode dstmode, const char *file, 71 int line); 72 static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd); 73 static __inline void ahd_restore_modes(struct ahd_softc *ahd, 74 ahd_mode_state state); 75 static __inline int ahd_is_paused(struct ahd_softc *ahd); 76 static __inline void ahd_pause(struct ahd_softc *ahd); 77 static __inline void ahd_unpause(struct ahd_softc *ahd); 78 79 static __inline void 80 ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 81 { 82 ahd->src_mode = src; 83 ahd->dst_mode = dst; 84 ahd->saved_src_mode = src; 85 ahd->saved_dst_mode = dst; 86 } 87 88 static __inline ahd_mode_state 89 ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 90 { 91 return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT)); 92 } 93 94 static __inline void 95 ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, 96 ahd_mode *src, ahd_mode *dst) 97 { 98 *src = (state & SRC_MODE) >> SRC_MODE_SHIFT; 99 *dst = (state & DST_MODE) >> DST_MODE_SHIFT; 100 } 101 102 static __inline void 103 ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) 104 { 105 if (ahd->src_mode == src && ahd->dst_mode == dst) 106 return; 107 #ifdef AHD_DEBUG 108 if (ahd->src_mode == AHD_MODE_UNKNOWN 109 || ahd->dst_mode == AHD_MODE_UNKNOWN) 110 panic("Setting mode prior to saving it.\n"); 111 if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 112 printf("%s: Setting mode 0x%x\n", ahd_name(ahd), 113 ahd_build_mode_state(ahd, src, dst)); 114 #endif 115 ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); 116 ahd->src_mode = src; 117 ahd->dst_mode = dst; 118 } 119 120 static __inline void 121 ahd_update_modes(struct ahd_softc *ahd) 122 { 123 ahd_mode_state mode_ptr; 124 ahd_mode src; 125 ahd_mode dst; 126 127 mode_ptr = ahd_inb(ahd, MODE_PTR); 128 #ifdef AHD_DEBUG 129 if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) 130 printf("Reading mode 0x%x\n", mode_ptr); 131 #endif 132 ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); 133 ahd_known_modes(ahd, src, dst); 134 } 135 136 static __inline void 137 ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 138 ahd_mode dstmode, const char *file, int line) 139 { 140 #ifdef AHD_DEBUG 141 if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0 142 || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) { 143 panic("%s:%s:%d: Mode assertion failed.\n", 144 ahd_name(ahd), file, line); 145 } 146 #endif 147 } 148 149 static __inline ahd_mode_state 150 ahd_save_modes(struct ahd_softc *ahd) 151 { 152 if (ahd->src_mode == AHD_MODE_UNKNOWN 153 || ahd->dst_mode == AHD_MODE_UNKNOWN) 154 ahd_update_modes(ahd); 155 156 return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode)); 157 } 158 159 static __inline void 160 ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state) 161 { 162 ahd_mode src; 163 ahd_mode dst; 164 165 ahd_extract_mode_state(ahd, state, &src, &dst); 166 ahd_set_modes(ahd, src, dst); 167 } 168 169 #define AHD_ASSERT_MODES(ahd, source, dest) \ 170 ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__); 171 172 /* 173 * Determine whether the sequencer has halted code execution. 174 * Returns non-zero status if the sequencer is stopped. 175 */ 176 static __inline int 177 ahd_is_paused(struct ahd_softc *ahd) 178 { 179 return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0); 180 } 181 182 /* 183 * Request that the sequencer stop and wait, indefinitely, for it 184 * to stop. The sequencer will only acknowledge that it is paused 185 * once it has reached an instruction boundary and PAUSEDIS is 186 * cleared in the SEQCTL register. The sequencer may use PAUSEDIS 187 * for critical sections. 188 */ 189 static __inline void 190 ahd_pause(struct ahd_softc *ahd) 191 { 192 ahd_outb(ahd, HCNTRL, ahd->pause); 193 194 /* 195 * Since the sequencer can disable pausing in a critical section, we 196 * must loop until it actually stops. 197 */ 198 while (ahd_is_paused(ahd) == 0) 199 ; 200 } 201 202 /* 203 * Allow the sequencer to continue program execution. 204 * We check here to ensure that no additional interrupt 205 * sources that would cause the sequencer to halt have been 206 * asserted. If, for example, a SCSI bus reset is detected 207 * while we are fielding a different, pausing, interrupt type, 208 * we don't want to release the sequencer before going back 209 * into our interrupt handler and dealing with this new 210 * condition. 211 */ 212 static __inline void 213 ahd_unpause(struct ahd_softc *ahd) 214 { 215 /* 216 * Automatically restore our modes to those saved 217 * prior to the first change of the mode. 218 */ 219 if (ahd->saved_src_mode != AHD_MODE_UNKNOWN 220 && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) 221 ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 222 223 if ((ahd_inb(ahd, INTSTAT) & ~(SWTMINT | CMDCMPLT)) == 0) 224 ahd_outb(ahd, HCNTRL, ahd->unpause); 225 226 ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); 227 } 228 229 /*********************** Scatter Gather List Handling *************************/ 230 static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 231 void *sgptr, bus_addr_t addr, 232 bus_size_t len, int last); 233 static __inline void ahd_setup_scb_common(struct ahd_softc *ahd, 234 struct scb *scb); 235 static __inline void ahd_setup_data_scb(struct ahd_softc *ahd, 236 struct scb *scb); 237 static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd, 238 struct scb *scb); 239 240 static __inline void * 241 ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 242 void *sgptr, bus_addr_t addr, bus_size_t len, int last) 243 { 244 scb->sg_count++; 245 if (sizeof(bus_addr_t) > 4 246 && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 247 struct ahd_dma64_seg *sg; 248 249 sg = (struct ahd_dma64_seg *)sgptr; 250 sg->addr = ahd_htole64(addr); 251 sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); 252 return (sg + 1); 253 } else { 254 struct ahd_dma_seg *sg; 255 256 sg = (struct ahd_dma_seg *)sgptr; 257 sg->addr = ahd_htole32(addr & 0xFFFFFFFF); 258 sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) 259 | (last ? AHD_DMA_LAST_SEG : 0)); 260 return (sg + 1); 261 } 262 } 263 264 static __inline void 265 ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) 266 { 267 /* XXX Handle target mode SCBs. */ 268 scb->crc_retry_count = 0; 269 if ((scb->flags & SCB_PACKETIZED) != 0) { 270 /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 271 scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE; 272 scb->hscb->task_management = 0; 273 /* 274 * For Rev A short lun workaround. 275 */ 276 scb->hscb->pkt_long_lun[6] = scb->hscb->lun; 277 } 278 279 if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 280 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 281 scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 282 ahd_htole32(scb->sense_busaddr); 283 } 284 285 static __inline void 286 ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 287 { 288 /* 289 * Copy the first SG into the "current" data ponter area. 290 */ 291 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 292 struct ahd_dma64_seg *sg; 293 294 sg = (struct ahd_dma64_seg *)scb->sg_list; 295 scb->hscb->dataptr = sg->addr; 296 scb->hscb->datacnt = sg->len; 297 } else { 298 struct ahd_dma_seg *sg; 299 300 sg = (struct ahd_dma_seg *)scb->sg_list; 301 scb->hscb->dataptr = sg->addr; 302 if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 303 uint64_t high_addr; 304 305 high_addr = ahd_le32toh(sg->len) & 0x7F000000; 306 scb->hscb->dataptr |= ahd_htole64(high_addr << 8); 307 } 308 scb->hscb->datacnt = sg->len; 309 } 310 /* 311 * Note where to find the SG entries in bus space. 312 * We also set the full residual flag which the 313 * sequencer will clear as soon as a data transfer 314 * occurs. 315 */ 316 scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 317 } 318 319 static __inline void 320 ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 321 { 322 scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 323 scb->hscb->dataptr = 0; 324 scb->hscb->datacnt = 0; 325 } 326 327 /************************** Memory mapping routines ***************************/ 328 static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 329 static __inline void * 330 ahd_sg_bus_to_virt(struct ahd_softc *ahd, 331 struct scb *scb, 332 uint32_t sg_busaddr); 333 static __inline uint32_t 334 ahd_sg_virt_to_bus(struct ahd_softc *ahd, 335 struct scb *scb, 336 void *sg); 337 static __inline void ahd_sync_scb(struct ahd_softc *ahd, 338 struct scb *scb, int op); 339 static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 340 struct scb *scb, int op); 341 static __inline void ahd_sync_sense(struct ahd_softc *ahd, 342 struct scb *scb, int op); 343 static __inline uint32_t 344 ahd_targetcmd_offset(struct ahd_softc *ahd, 345 u_int index); 346 347 static __inline size_t 348 ahd_sg_size(struct ahd_softc *ahd) 349 { 350 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 351 return (sizeof(struct ahd_dma64_seg)); 352 return (sizeof(struct ahd_dma_seg)); 353 } 354 355 static __inline void * 356 ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 357 { 358 bus_addr_t sg_offset; 359 360 /* sg_list_phys points to entry 1, not 0 */ 361 sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 362 return ((uint8_t *)scb->sg_list + sg_offset); 363 } 364 365 static __inline uint32_t 366 ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 367 { 368 bus_addr_t sg_offset; 369 370 /* sg_list_phys points to entry 1, not 0 */ 371 sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 372 - ahd_sg_size(ahd); 373 374 return (scb->sg_list_busaddr + sg_offset); 375 } 376 377 static __inline void 378 ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 379 { 380 ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 381 scb->hscb_map->dmamap, 382 /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 383 /*len*/sizeof(*scb->hscb), op); 384 } 385 386 static __inline void 387 ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 388 { 389 if (scb->sg_count == 0) 390 return; 391 392 ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 393 scb->sg_map->dmamap, 394 /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 395 /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 396 } 397 398 static __inline void 399 ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 400 { 401 ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 402 scb->sense_map->dmamap, 403 /*offset*/scb->sense_busaddr, 404 /*len*/AHD_SENSE_BUFSIZE, op); 405 } 406 407 static __inline uint32_t 408 ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 409 { 410 return (((uint8_t *)&ahd->targetcmds[index]) 411 - (uint8_t *)ahd->qoutfifo); 412 } 413 414 /*********************** Miscelaneous Support Functions ***********************/ 415 static __inline void ahd_complete_scb(struct ahd_softc *ahd, 416 struct scb *scb); 417 static __inline void ahd_update_residual(struct ahd_softc *ahd, 418 struct scb *scb); 419 static __inline struct ahd_initiator_tinfo * 420 ahd_fetch_transinfo(struct ahd_softc *ahd, 421 char channel, u_int our_id, 422 u_int remote_id, 423 struct ahd_tmode_tstate **tstate); 424 static __inline uint16_t 425 ahd_inw(struct ahd_softc *ahd, u_int port); 426 static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 427 u_int value); 428 static __inline uint32_t 429 ahd_inl(struct ahd_softc *ahd, u_int port); 430 static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 431 uint32_t value); 432 static __inline uint64_t 433 ahd_inq(struct ahd_softc *ahd, u_int port); 434 static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 435 uint64_t value); 436 static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 437 static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 438 static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 439 static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 440 static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 441 static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 442 static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 443 static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 444 static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 445 static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 446 static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 447 static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 448 static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 449 static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 450 static __inline uint32_t 451 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 452 static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 453 struct scb *scb); 454 static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 455 static __inline uint8_t * 456 ahd_get_sense_buf(struct ahd_softc *ahd, 457 struct scb *scb); 458 static __inline uint32_t 459 ahd_get_sense_bufaddr(struct ahd_softc *ahd, 460 struct scb *scb); 461 462 static __inline void 463 ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 464 { 465 uint32_t sgptr; 466 467 sgptr = ahd_le32toh(scb->hscb->sgptr); 468 if ((sgptr & SG_STATUS_VALID) != 0) 469 ahd_handle_scb_status(ahd, scb); 470 else 471 ahd_done(ahd, scb); 472 } 473 474 /* 475 * Determine whether the sequencer reported a residual 476 * for this SCB/transaction. 477 */ 478 static __inline void 479 ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 480 { 481 uint32_t sgptr; 482 483 sgptr = ahd_le32toh(scb->hscb->sgptr); 484 if ((sgptr & SG_STATUS_VALID) != 0) 485 ahd_calc_residual(ahd, scb); 486 } 487 488 /* 489 * Return pointers to the transfer negotiation information 490 * for the specified our_id/remote_id pair. 491 */ 492 static __inline struct ahd_initiator_tinfo * 493 ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 494 u_int remote_id, struct ahd_tmode_tstate **tstate) 495 { 496 /* 497 * Transfer data structures are stored from the perspective 498 * of the target role. Since the parameters for a connection 499 * in the initiator role to a given target are the same as 500 * when the roles are reversed, we pretend we are the target. 501 */ 502 if (channel == 'B') 503 our_id += 8; 504 *tstate = ahd->enabled_targets[our_id]; 505 return (&(*tstate)->transinfo[remote_id]); 506 } 507 508 #define AHD_COPY_COL_IDX(dst, src) \ 509 do { \ 510 dst->hscb->scsiid = src->hscb->scsiid; \ 511 dst->hscb->lun = src->hscb->lun; \ 512 } while (0) 513 514 static __inline uint16_t 515 ahd_inw(struct ahd_softc *ahd, u_int port) 516 { 517 return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); 518 } 519 520 static __inline void 521 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 522 { 523 ahd_outb(ahd, port, value & 0xFF); 524 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 525 } 526 527 static __inline uint32_t 528 ahd_inl(struct ahd_softc *ahd, u_int port) 529 { 530 return ((ahd_inb(ahd, port)) 531 | (ahd_inb(ahd, port+1) << 8) 532 | (ahd_inb(ahd, port+2) << 16) 533 | (ahd_inb(ahd, port+3) << 24)); 534 } 535 536 static __inline void 537 ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 538 { 539 ahd_outb(ahd, port, (value) & 0xFF); 540 ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 541 ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 542 ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 543 } 544 545 static __inline uint64_t 546 ahd_inq(struct ahd_softc *ahd, u_int port) 547 { 548 return ((ahd_inb(ahd, port)) 549 | (ahd_inb(ahd, port+1) << 8) 550 | (ahd_inb(ahd, port+2) << 16) 551 | (ahd_inb(ahd, port+3) << 24) 552 | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 553 | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 554 | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 555 | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 556 } 557 558 static __inline void 559 ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 560 { 561 ahd_outb(ahd, port, value & 0xFF); 562 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 563 ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 564 ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 565 ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 566 ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 567 ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 568 ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 569 } 570 571 static __inline u_int 572 ahd_get_scbptr(struct ahd_softc *ahd) 573 { 574 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 575 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 576 return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 577 } 578 579 static __inline void 580 ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 581 { 582 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 583 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 584 ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 585 ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 586 } 587 588 static __inline u_int 589 ahd_get_hnscb_qoff(struct ahd_softc *ahd) 590 { 591 return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 592 } 593 594 static __inline void 595 ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 596 { 597 ahd_outw_atomic(ahd, HNSCB_QOFF, value); 598 } 599 600 static __inline u_int 601 ahd_get_hescb_qoff(struct ahd_softc *ahd) 602 { 603 return (ahd_inb(ahd, HESCB_QOFF)); 604 } 605 606 static __inline void 607 ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 608 { 609 ahd_outb(ahd, HESCB_QOFF, value); 610 } 611 612 static __inline u_int 613 ahd_get_snscb_qoff(struct ahd_softc *ahd) 614 { 615 u_int oldvalue; 616 617 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 618 oldvalue = ahd_inw(ahd, SNSCB_QOFF); 619 ahd_outw(ahd, SNSCB_QOFF, oldvalue); 620 return (oldvalue); 621 } 622 623 static __inline void 624 ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 625 { 626 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 627 ahd_outw(ahd, SNSCB_QOFF, value); 628 } 629 630 static __inline u_int 631 ahd_get_sescb_qoff(struct ahd_softc *ahd) 632 { 633 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 634 return (ahd_inb(ahd, SESCB_QOFF)); 635 } 636 637 static __inline void 638 ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 639 { 640 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 641 ahd_outb(ahd, SESCB_QOFF, value); 642 } 643 644 static __inline u_int 645 ahd_get_sdscb_qoff(struct ahd_softc *ahd) 646 { 647 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 648 return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 649 } 650 651 static __inline void 652 ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 653 { 654 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 655 ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 656 ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 657 } 658 659 static __inline u_int 660 ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 661 { 662 u_int value; 663 664 /* 665 * Workaround PCI-X Rev A. hardware bug. 666 * After a host read of SCB memory, the chip 667 * may become confused into thinking prefetch 668 * was required. This starts the discard timer 669 * running and can cause an unexpected discard 670 * timer interrupt. The work around is to read 671 * a normal register prior to the exhaustion of 672 * the discard timer. The mode pointer register 673 * has no side effects and so serves well for 674 * this purpose. 675 * 676 * Razor #528 677 */ 678 value = ahd_inb(ahd, offset); 679 ahd_inb(ahd, MODE_PTR); 680 return (value); 681 } 682 683 static __inline u_int 684 ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 685 { 686 return (ahd_inb_scbram(ahd, offset) 687 | (ahd_inb_scbram(ahd, offset+1) << 8)); 688 } 689 690 static __inline uint32_t 691 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 692 { 693 return (ahd_inb_scbram(ahd, offset) 694 | (ahd_inb_scbram(ahd, offset+1) << 8) 695 | (ahd_inb_scbram(ahd, offset+2) << 16) 696 | (ahd_inb_scbram(ahd, offset+3) << 24)); 697 } 698 699 static __inline struct scb * 700 ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 701 { 702 struct scb* scb; 703 704 if (tag >= AHD_SCB_MAX) 705 return (NULL); 706 scb = ahd->scb_data.scbindex[tag]; 707 if (scb != NULL) 708 ahd_sync_scb(ahd, scb, 709 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 710 return (scb); 711 } 712 713 static __inline void 714 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 715 { 716 struct hardware_scb *q_hscb; 717 uint32_t saved_hscb_busaddr; 718 719 /* 720 * Our queuing method is a bit tricky. The card 721 * knows in advance which HSCB (by address) to download, 722 * and we can't disappoint it. To achieve this, the next 723 * HSCB to download is saved off in ahd->next_queued_hscb. 724 * When we are called to queue "an arbitrary scb", 725 * we copy the contents of the incoming HSCB to the one 726 * the sequencer knows about, swap HSCB pointers and 727 * finally assign the SCB to the tag indexed location 728 * in the scb_array. This makes sure that we can still 729 * locate the correct SCB by SCB_TAG. 730 */ 731 q_hscb = ahd->next_queued_hscb; 732 saved_hscb_busaddr = q_hscb->hscb_busaddr; 733 memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 734 q_hscb->hscb_busaddr = saved_hscb_busaddr; 735 q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 736 737 /* Now swap HSCB pointers. */ 738 ahd->next_queued_hscb = scb->hscb; 739 scb->hscb = q_hscb; 740 741 /* Now define the mapping from tag to SCB in the scbindex */ 742 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 743 } 744 745 /* 746 * Tell the sequencer about a new transaction to execute. 747 */ 748 static __inline void 749 ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 750 { 751 ahd_swap_with_next_hscb(ahd, scb); 752 753 if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 754 panic("Attempt to queue invalid SCB tag %x\n", 755 SCB_GET_TAG(scb)); 756 757 /* 758 * Keep a history of SCBs we've downloaded in the qinfifo. 759 */ 760 ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 761 ahd->qinfifonext++; 762 763 if (scb->sg_count != 0) 764 ahd_setup_data_scb(ahd, scb); 765 else 766 ahd_setup_noxfer_scb(ahd, scb); 767 ahd_setup_scb_common(ahd, scb); 768 769 /* 770 * Make sure our data is consistant from the 771 * perspective of the adapter. 772 */ 773 ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 774 775 #ifdef AHD_DEBUG 776 if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 777 printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 778 ahd_name(ahd), 779 SCB_GET_TAG(scb), scb->hscb->hscb_busaddr, 780 (u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF), 781 (u_int)(scb->hscb->dataptr & 0xFFFFFFFF), 782 scb->hscb->datacnt); 783 } 784 #endif 785 /* Tell the adapter about the newly queued SCB */ 786 ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 787 } 788 789 static __inline uint8_t * 790 ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 791 { 792 return (scb->sense_data); 793 } 794 795 static __inline uint32_t 796 ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 797 { 798 return (scb->sense_busaddr); 799 } 800 801 /************************** Interrupt Processing ******************************/ 802 static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 803 static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 804 static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 805 static __inline void ahd_intr(struct ahd_softc *ahd); 806 807 static __inline void 808 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 809 { 810 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 811 /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op); 812 } 813 814 static __inline void 815 ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 816 { 817 #ifdef AHD_TARGET_MODE 818 if ((ahd->flags & AHD_TARGETROLE) != 0) { 819 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 820 ahd->shared_data_dmamap, 821 ahd_targetcmd_offset(ahd, 0), 822 sizeof(struct target_cmd) * AHD_TMODE_CMDS, 823 op); 824 } 825 #endif 826 } 827 828 /* 829 * See if the firmware has posted any completed commands 830 * into our in-core command complete fifos. 831 */ 832 #define AHD_RUN_QOUTFIFO 0x1 833 #define AHD_RUN_TQINFIFO 0x2 834 static __inline u_int 835 ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 836 { 837 u_int retval; 838 839 retval = 0; 840 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 841 /*offset*/ahd->qoutfifonext, /*len*/2, 842 BUS_DMASYNC_POSTREAD); 843 if ((ahd->qoutfifo[ahd->qoutfifonext] 844 & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) 845 retval |= AHD_RUN_QOUTFIFO; 846 #ifdef AHD_TARGET_MODE 847 if ((ahd->flags & AHD_TARGETROLE) != 0 848 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 849 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 850 ahd->shared_data_dmamap, 851 ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 852 /*len*/sizeof(struct target_cmd), 853 BUS_DMASYNC_POSTREAD); 854 if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 855 retval |= AHD_RUN_TQINFIFO; 856 } 857 #endif 858 return (retval); 859 } 860 861 /* 862 * Catch an interrupt from the adapter 863 */ 864 static __inline void 865 ahd_intr(struct ahd_softc *ahd) 866 { 867 u_int intstat; 868 869 if ((ahd->pause & INTEN) == 0) { 870 /* 871 * Our interrupt is not enabled on the chip 872 * and may be disabled for re-entrancy reasons, 873 * so just return. This is likely just a shared 874 * interrupt. 875 */ 876 return; 877 } 878 879 /* 880 * Instead of directly reading the interrupt status register, 881 * infer the cause of the interrupt by checking our in-core 882 * completion queues. This avoids a costly PCI bus read in 883 * most cases. 884 */ 885 if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 886 && (ahd_check_cmdcmpltqueues(ahd) != 0)) 887 intstat = CMDCMPLT; 888 else 889 intstat = ahd_inb(ahd, INTSTAT); 890 891 if (intstat & CMDCMPLT) { 892 ahd_outb(ahd, CLRINT, CLRCMDINT); 893 894 /* 895 * Ensure that the chip sees that we've cleared 896 * this interrupt before we walk the output fifo. 897 * Otherwise, we may, due to posted bus writes, 898 * clear the interrupt after we finish the scan, 899 * and after the sequencer has added new entries 900 * and asserted the interrupt again. 901 */ 902 if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 903 if (ahd_is_paused(ahd)) { 904 /* 905 * Potentially lost SEQINT. 906 * If SEQINTCODE is non-zero, 907 * simulate the SEQINT. 908 */ 909 if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT) 910 intstat |= SEQINT; 911 } 912 } else { 913 ahd_flush_device_writes(ahd); 914 } 915 ahd_run_qoutfifo(ahd); 916 #ifdef AHD_TARGET_MODE 917 if ((ahd->flags & AHD_TARGETROLE) != 0) 918 ahd_run_tqinfifo(ahd, /*paused*/FALSE); 919 #endif 920 } 921 922 if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) 923 /* Hot eject */ 924 return; 925 926 if ((intstat & INT_PEND) == 0) 927 return; 928 929 if (intstat & HWERRINT) { 930 ahd_handle_hwerrint(ahd); 931 return; 932 } 933 934 if ((intstat & (PCIINT|SPLTINT)) != 0) { 935 ahd->bus_intr(ahd); 936 return; 937 } 938 939 if ((intstat & SEQINT) != 0) 940 ahd_handle_seqint(ahd, intstat); 941 942 if ((intstat & SCSIINT) != 0) 943 ahd_handle_scsiint(ahd, intstat); 944 } 945 946 #endif /* _AIC79XX_INLINE_H_ */ 947