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#36 $ 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("Setting mode 0x%x\n", 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 if ((scb->flags & SCB_PACKETIZED) != 0) { 269 /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 270 scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE; 271 scb->hscb->task_management = 0; 272 /* 273 * For Rev A short lun workaround. 274 */ 275 scb->hscb->pkt_long_lun[6] = scb->hscb->lun; 276 } 277 278 if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 279 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 280 scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 281 ahd_htole32(scb->sense_busaddr); 282 } 283 284 static __inline void 285 ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 286 { 287 /* 288 * Copy the first SG into the "current" data ponter area. 289 */ 290 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 291 struct ahd_dma64_seg *sg; 292 293 sg = (struct ahd_dma64_seg *)scb->sg_list; 294 scb->hscb->dataptr = sg->addr; 295 scb->hscb->datacnt = sg->len; 296 } else { 297 struct ahd_dma_seg *sg; 298 299 sg = (struct ahd_dma_seg *)scb->sg_list; 300 scb->hscb->dataptr = sg->addr; 301 if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 302 uint64_t high_addr; 303 304 high_addr = ahd_le32toh(sg->len) & 0x7F000000; 305 scb->hscb->dataptr |= ahd_htole64(high_addr << 8); 306 } 307 scb->hscb->datacnt = sg->len; 308 } 309 /* 310 * Note where to find the SG entries in bus space. 311 * We also set the full residual flag which the 312 * sequencer will clear as soon as a data transfer 313 * occurs. 314 */ 315 scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 316 } 317 318 static __inline void 319 ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 320 { 321 scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); 322 scb->hscb->dataptr = 0; 323 scb->hscb->datacnt = 0; 324 } 325 326 /************************** Memory mapping routines ***************************/ 327 static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 328 static __inline void * 329 ahd_sg_bus_to_virt(struct ahd_softc *ahd, 330 struct scb *scb, 331 uint32_t sg_busaddr); 332 static __inline uint32_t 333 ahd_sg_virt_to_bus(struct ahd_softc *ahd, 334 struct scb *scb, 335 void *sg); 336 static __inline void ahd_sync_scb(struct ahd_softc *ahd, 337 struct scb *scb, int op); 338 static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 339 struct scb *scb, int op); 340 static __inline void ahd_sync_sense(struct ahd_softc *ahd, 341 struct scb *scb, int op); 342 static __inline uint32_t 343 ahd_targetcmd_offset(struct ahd_softc *ahd, 344 u_int index); 345 346 static __inline size_t 347 ahd_sg_size(struct ahd_softc *ahd) 348 { 349 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 350 return (sizeof(struct ahd_dma64_seg)); 351 return (sizeof(struct ahd_dma_seg)); 352 } 353 354 static __inline void * 355 ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 356 { 357 bus_addr_t sg_offset; 358 359 /* sg_list_phys points to entry 1, not 0 */ 360 sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 361 return ((uint8_t *)scb->sg_list + sg_offset); 362 } 363 364 static __inline uint32_t 365 ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 366 { 367 bus_addr_t sg_offset; 368 369 /* sg_list_phys points to entry 1, not 0 */ 370 sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 371 - ahd_sg_size(ahd); 372 373 return (scb->sg_list_busaddr + sg_offset); 374 } 375 376 static __inline void 377 ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 378 { 379 ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 380 scb->hscb_map->dmamap, 381 /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 382 /*len*/sizeof(*scb->hscb), op); 383 } 384 385 static __inline void 386 ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 387 { 388 if (scb->sg_count == 0) 389 return; 390 391 ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 392 scb->sg_map->dmamap, 393 /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 394 /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 395 } 396 397 static __inline void 398 ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 399 { 400 ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 401 scb->sense_map->dmamap, 402 /*offset*/scb->sense_busaddr, 403 /*len*/AHD_SENSE_BUFSIZE, op); 404 } 405 406 static __inline uint32_t 407 ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 408 { 409 return (((uint8_t *)&ahd->targetcmds[index]) 410 - (uint8_t *)ahd->qoutfifo); 411 } 412 413 /*********************** Miscelaneous Support Functions ***********************/ 414 static __inline void ahd_complete_scb(struct ahd_softc *ahd, 415 struct scb *scb); 416 static __inline void ahd_update_residual(struct ahd_softc *ahd, 417 struct scb *scb); 418 static __inline struct ahd_initiator_tinfo * 419 ahd_fetch_transinfo(struct ahd_softc *ahd, 420 char channel, u_int our_id, 421 u_int remote_id, 422 struct ahd_tmode_tstate **tstate); 423 static __inline uint16_t 424 ahd_inw(struct ahd_softc *ahd, u_int port); 425 static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 426 u_int value); 427 static __inline uint32_t 428 ahd_inl(struct ahd_softc *ahd, u_int port); 429 static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 430 uint32_t value); 431 static __inline uint64_t 432 ahd_inq(struct ahd_softc *ahd, u_int port); 433 static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 434 uint64_t value); 435 static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 436 static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 437 static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 438 static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 439 static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 440 static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 441 static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 442 static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 443 static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 444 static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 445 static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 446 static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 447 static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 448 static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 449 static __inline uint32_t 450 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 451 static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 452 struct scb *scb); 453 static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 454 static __inline uint8_t * 455 ahd_get_sense_buf(struct ahd_softc *ahd, 456 struct scb *scb); 457 static __inline uint32_t 458 ahd_get_sense_bufaddr(struct ahd_softc *ahd, 459 struct scb *scb); 460 461 static __inline void 462 ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 463 { 464 uint32_t sgptr; 465 466 sgptr = ahd_le32toh(scb->hscb->sgptr); 467 if ((sgptr & SG_STATUS_VALID) != 0) 468 ahd_handle_scb_status(ahd, scb); 469 else 470 ahd_done(ahd, scb); 471 } 472 473 /* 474 * Determine whether the sequencer reported a residual 475 * for this SCB/transaction. 476 */ 477 static __inline void 478 ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 479 { 480 uint32_t sgptr; 481 482 sgptr = ahd_le32toh(scb->hscb->sgptr); 483 if ((sgptr & SG_STATUS_VALID) != 0) 484 ahd_calc_residual(ahd, scb); 485 } 486 487 /* 488 * Return pointers to the transfer negotiation information 489 * for the specified our_id/remote_id pair. 490 */ 491 static __inline struct ahd_initiator_tinfo * 492 ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 493 u_int remote_id, struct ahd_tmode_tstate **tstate) 494 { 495 /* 496 * Transfer data structures are stored from the perspective 497 * of the target role. Since the parameters for a connection 498 * in the initiator role to a given target are the same as 499 * when the roles are reversed, we pretend we are the target. 500 */ 501 if (channel == 'B') 502 our_id += 8; 503 *tstate = ahd->enabled_targets[our_id]; 504 return (&(*tstate)->transinfo[remote_id]); 505 } 506 507 #define AHD_COPY_COL_IDX(dst, src) \ 508 do { \ 509 dst->hscb->scsiid = src->hscb->scsiid; \ 510 dst->hscb->lun = src->hscb->lun; \ 511 } while (0) 512 513 static __inline uint16_t 514 ahd_inw(struct ahd_softc *ahd, u_int port) 515 { 516 return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); 517 } 518 519 static __inline void 520 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 521 { 522 ahd_outb(ahd, port, value & 0xFF); 523 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 524 } 525 526 static __inline uint32_t 527 ahd_inl(struct ahd_softc *ahd, u_int port) 528 { 529 return ((ahd_inb(ahd, port)) 530 | (ahd_inb(ahd, port+1) << 8) 531 | (ahd_inb(ahd, port+2) << 16) 532 | (ahd_inb(ahd, port+3) << 24)); 533 } 534 535 static __inline void 536 ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 537 { 538 ahd_outb(ahd, port, (value) & 0xFF); 539 ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 540 ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 541 ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 542 } 543 544 static __inline uint64_t 545 ahd_inq(struct ahd_softc *ahd, u_int port) 546 { 547 return ((ahd_inb(ahd, port)) 548 | (ahd_inb(ahd, port+1) << 8) 549 | (ahd_inb(ahd, port+2) << 16) 550 | (ahd_inb(ahd, port+3) << 24) 551 | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 552 | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 553 | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 554 | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 555 } 556 557 static __inline void 558 ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 559 { 560 ahd_outb(ahd, port, value & 0xFF); 561 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 562 ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 563 ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 564 ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 565 ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 566 ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 567 ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 568 } 569 570 static __inline u_int 571 ahd_get_scbptr(struct ahd_softc *ahd) 572 { 573 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 574 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 575 return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 576 } 577 578 static __inline void 579 ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 580 { 581 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 582 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 583 ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 584 ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 585 } 586 587 static __inline u_int 588 ahd_get_hnscb_qoff(struct ahd_softc *ahd) 589 { 590 return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 591 } 592 593 static __inline void 594 ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 595 { 596 ahd_outw_atomic(ahd, HNSCB_QOFF, value); 597 } 598 599 static __inline u_int 600 ahd_get_hescb_qoff(struct ahd_softc *ahd) 601 { 602 return (ahd_inb(ahd, HESCB_QOFF)); 603 } 604 605 static __inline void 606 ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 607 { 608 ahd_outb(ahd, HESCB_QOFF, value); 609 } 610 611 static __inline u_int 612 ahd_get_snscb_qoff(struct ahd_softc *ahd) 613 { 614 u_int oldvalue; 615 616 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 617 oldvalue = ahd_inw(ahd, SNSCB_QOFF); 618 ahd_outw(ahd, SNSCB_QOFF, oldvalue); 619 return (oldvalue); 620 } 621 622 static __inline void 623 ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 624 { 625 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 626 ahd_outw(ahd, SNSCB_QOFF, value); 627 } 628 629 static __inline u_int 630 ahd_get_sescb_qoff(struct ahd_softc *ahd) 631 { 632 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 633 return (ahd_inb(ahd, SESCB_QOFF)); 634 } 635 636 static __inline void 637 ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 638 { 639 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 640 ahd_outb(ahd, SESCB_QOFF, value); 641 } 642 643 static __inline u_int 644 ahd_get_sdscb_qoff(struct ahd_softc *ahd) 645 { 646 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 647 return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 648 } 649 650 static __inline void 651 ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 652 { 653 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 654 ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 655 ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 656 } 657 658 static __inline u_int 659 ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 660 { 661 u_int value; 662 663 /* 664 * Workaround PCI-X Rev A. hardware bug. 665 * After a host read of SCB memory, the chip 666 * may become confused into thinking prefetch 667 * was required. This starts the discard timer 668 * running and can cause an unexpected discard 669 * timer interrupt. The work around is to read 670 * a normal register prior to the exhaustion of 671 * the discard timer. The mode pointer register 672 * has no side effects and so serves well for 673 * this purpose. 674 * 675 * Razor #528 676 */ 677 value = ahd_inb(ahd, offset); 678 ahd_inb(ahd, MODE_PTR); 679 return (value); 680 } 681 682 static __inline u_int 683 ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 684 { 685 return (ahd_inb_scbram(ahd, offset) 686 | (ahd_inb_scbram(ahd, offset+1) << 8)); 687 } 688 689 static __inline uint32_t 690 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 691 { 692 return (ahd_inb_scbram(ahd, offset) 693 | (ahd_inb_scbram(ahd, offset+1) << 8) 694 | (ahd_inb_scbram(ahd, offset+2) << 16) 695 | (ahd_inb_scbram(ahd, offset+3) << 24)); 696 } 697 698 static __inline struct scb * 699 ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 700 { 701 struct scb* scb; 702 703 if (tag >= AHD_SCB_MAX) 704 return (NULL); 705 scb = ahd->scb_data.scbindex[tag]; 706 if (scb != NULL) 707 ahd_sync_scb(ahd, scb, 708 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 709 return (scb); 710 } 711 712 static __inline void 713 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 714 { 715 struct hardware_scb *q_hscb; 716 uint32_t saved_hscb_busaddr; 717 718 /* 719 * Our queuing method is a bit tricky. The card 720 * knows in advance which HSCB (by address) to download, 721 * and we can't disappoint it. To achieve this, the next 722 * HSCB to download is saved off in ahd->next_queued_hscb. 723 * When we are called to queue "an arbitrary scb", 724 * we copy the contents of the incoming HSCB to the one 725 * the sequencer knows about, swap HSCB pointers and 726 * finally assign the SCB to the tag indexed location 727 * in the scb_array. This makes sure that we can still 728 * locate the correct SCB by SCB_TAG. 729 */ 730 q_hscb = ahd->next_queued_hscb; 731 saved_hscb_busaddr = q_hscb->hscb_busaddr; 732 memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 733 q_hscb->hscb_busaddr = saved_hscb_busaddr; 734 q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 735 736 /* Now swap HSCB pointers. */ 737 ahd->next_queued_hscb = scb->hscb; 738 scb->hscb = q_hscb; 739 740 /* Now define the mapping from tag to SCB in the scbindex */ 741 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 742 } 743 744 /* 745 * Tell the sequencer about a new transaction to execute. 746 */ 747 static __inline void 748 ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 749 { 750 ahd_swap_with_next_hscb(ahd, scb); 751 752 if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 753 panic("Attempt to queue invalid SCB tag %x\n", 754 SCB_GET_TAG(scb)); 755 756 /* 757 * Keep a history of SCBs we've downloaded in the qinfifo. 758 */ 759 ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 760 ahd->qinfifonext++; 761 762 if (scb->sg_count != 0) 763 ahd_setup_data_scb(ahd, scb); 764 else 765 ahd_setup_noxfer_scb(ahd, scb); 766 ahd_setup_scb_common(ahd, scb); 767 768 /* 769 * Make sure our data is consistant from the 770 * perspective of the adapter. 771 */ 772 ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 773 774 #ifdef AHD_DEBUG 775 if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 776 printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 777 ahd_name(ahd), 778 SCB_GET_TAG(scb), scb->hscb->hscb_busaddr, 779 (u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF), 780 (u_int)(scb->hscb->dataptr & 0xFFFFFFFF), 781 scb->hscb->datacnt); 782 } 783 #endif 784 /* Tell the adapter about the newly queued SCB */ 785 ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 786 } 787 788 static __inline uint8_t * 789 ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 790 { 791 return (scb->sense_data); 792 } 793 794 static __inline uint32_t 795 ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 796 { 797 return (scb->sense_busaddr); 798 } 799 800 /************************** Interrupt Processing ******************************/ 801 static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 802 static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 803 static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 804 static __inline void ahd_intr(struct ahd_softc *ahd); 805 806 static __inline void 807 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 808 { 809 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 810 /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op); 811 } 812 813 static __inline void 814 ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 815 { 816 #ifdef AHD_TARGET_MODE 817 if ((ahd->flags & AHD_TARGETROLE) != 0) { 818 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 819 ahd->shared_data_dmamap, 820 ahd_targetcmd_offset(ahd, 0), 821 sizeof(struct target_cmd) * AHD_TMODE_CMDS, 822 op); 823 } 824 #endif 825 } 826 827 /* 828 * See if the firmware has posted any completed commands 829 * into our in-core command complete fifos. 830 */ 831 #define AHD_RUN_QOUTFIFO 0x1 832 #define AHD_RUN_TQINFIFO 0x2 833 static __inline u_int 834 ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 835 { 836 u_int retval; 837 838 retval = 0; 839 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, 840 /*offset*/ahd->qoutfifonext, /*len*/2, 841 BUS_DMASYNC_POSTREAD); 842 if ((ahd->qoutfifo[ahd->qoutfifonext] 843 & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) 844 retval |= AHD_RUN_QOUTFIFO; 845 #ifdef AHD_TARGET_MODE 846 if ((ahd->flags & AHD_TARGETROLE) != 0 847 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 848 ahd_dmamap_sync(ahd, ahd->shared_data_dmat, 849 ahd->shared_data_dmamap, 850 ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 851 /*len*/sizeof(struct target_cmd), 852 BUS_DMASYNC_POSTREAD); 853 if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 854 retval |= AHD_RUN_TQINFIFO; 855 } 856 #endif 857 return (retval); 858 } 859 860 /* 861 * Catch an interrupt from the adapter 862 */ 863 static __inline void 864 ahd_intr(struct ahd_softc *ahd) 865 { 866 u_int intstat; 867 868 if ((ahd->pause & INTEN) == 0) { 869 /* 870 * Our interrupt is not enabled on the chip 871 * and may be disabled for re-entrancy reasons, 872 * so just return. This is likely just a shared 873 * interrupt. 874 */ 875 return; 876 } 877 878 /* 879 * Instead of directly reading the interrupt status register, 880 * infer the cause of the interrupt by checking our in-core 881 * completion queues. This avoids a costly PCI bus read in 882 * most cases. 883 */ 884 if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 885 && (ahd_check_cmdcmpltqueues(ahd) != 0)) 886 intstat = CMDCMPLT; 887 else 888 intstat = ahd_inb(ahd, INTSTAT); 889 890 if (intstat & CMDCMPLT) { 891 ahd_outb(ahd, CLRINT, CLRCMDINT); 892 893 /* 894 * Ensure that the chip sees that we've cleared 895 * this interrupt before we walk the output fifo. 896 * Otherwise, we may, due to posted bus writes, 897 * clear the interrupt after we finish the scan, 898 * and after the sequencer has added new entries 899 * and asserted the interrupt again. 900 */ 901 ahd_flush_device_writes(ahd); 902 ahd_run_qoutfifo(ahd); 903 #ifdef AHD_TARGET_MODE 904 if ((ahd->flags & AHD_TARGETROLE) != 0) 905 ahd_run_tqinfifo(ahd, /*paused*/FALSE); 906 #endif 907 } 908 909 if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) 910 /* Hot eject */ 911 return; 912 913 if ((intstat & INT_PEND) == 0) 914 return; 915 916 if (intstat & HWERRINT) { 917 ahd_handle_hwerrint(ahd); 918 return; 919 } 920 921 if ((intstat & (PCIINT|SPLTINT)) != 0) { 922 ahd->bus_intr(ahd); 923 return; 924 } 925 926 if ((intstat & SEQINT) != 0) 927 ahd_handle_seqint(ahd, intstat); 928 929 if ((intstat & SCSIINT) != 0) 930 ahd_handle_scsiint(ahd, intstat); 931 } 932 933 #endif /* _AIC79XX_INLINE_H_ */ 934