aic79xx_inline.h revision 331722
1/*- 2 * Inline routines shareable across OS platforms. 3 * 4 * Copyright (c) 1994-2001 Justin T. Gibbs. 5 * Copyright (c) 2000-2003 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#57 $ 41 * 42 * $FreeBSD: stable/11/sys/dev/aic7xxx/aic79xx_inline.h 331722 2018-03-29 02:50:57Z eadler $ 43 */ 44 45#ifndef _AIC79XX_INLINE_H_ 46#define _AIC79XX_INLINE_H_ 47 48/******************************** Debugging ***********************************/ 49static __inline char *ahd_name(struct ahd_softc *ahd); 50 51static __inline char * 52ahd_name(struct ahd_softc *ahd) 53{ 54 return (ahd->name); 55} 56 57/************************ Sequencer Execution Control *************************/ 58static __inline void ahd_known_modes(struct ahd_softc *ahd, 59 ahd_mode src, ahd_mode dst); 60static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, 61 ahd_mode src, 62 ahd_mode dst); 63static __inline void ahd_extract_mode_state(struct ahd_softc *ahd, 64 ahd_mode_state state, 65 ahd_mode *src, ahd_mode *dst); 66static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, 67 ahd_mode dst); 68static __inline void ahd_update_modes(struct ahd_softc *ahd); 69static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, 70 ahd_mode dstmode, const char *file, 71 int line); 72static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd); 73static __inline void ahd_restore_modes(struct ahd_softc *ahd, 74 ahd_mode_state state); 75static __inline int ahd_is_paused(struct ahd_softc *ahd); 76static __inline void ahd_pause(struct ahd_softc *ahd); 77static __inline void ahd_unpause(struct ahd_softc *ahd); 78 79static __inline void 80ahd_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 88static __inline ahd_mode_state 89ahd_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 94static __inline void 95ahd_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 102static __inline void 103ahd_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 120static __inline void 121ahd_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 136static __inline void 137ahd_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 149static __inline ahd_mode_state 150ahd_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 159static __inline void 160ahd_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 */ 176static __inline int 177ahd_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 */ 189static __inline void 190ahd_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 */ 212static __inline void 213ahd_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 if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0) 222 ahd_reset_cmds_pending(ahd); 223 ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); 224 } 225 226 if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0) 227 ahd_outb(ahd, HCNTRL, ahd->unpause); 228 229 ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); 230} 231 232/*********************** Scatter Gather List Handling *************************/ 233static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 234 void *sgptr, bus_addr_t addr, 235 bus_size_t len, int last); 236static __inline void ahd_setup_scb_common(struct ahd_softc *ahd, 237 struct scb *scb); 238static __inline void ahd_setup_data_scb(struct ahd_softc *ahd, 239 struct scb *scb); 240static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd, 241 struct scb *scb); 242 243static __inline void * 244ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, 245 void *sgptr, bus_addr_t addr, bus_size_t len, int last) 246{ 247 scb->sg_count++; 248 if (sizeof(bus_addr_t) > 4 249 && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 250 struct ahd_dma64_seg *sg; 251 252 sg = (struct ahd_dma64_seg *)sgptr; 253 sg->addr = aic_htole64(addr); 254 sg->len = aic_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); 255 return (sg + 1); 256 } else { 257 struct ahd_dma_seg *sg; 258 259 sg = (struct ahd_dma_seg *)sgptr; 260 sg->addr = aic_htole32(addr & 0xFFFFFFFF); 261 sg->len = aic_htole32(len | ((addr >> 8) & 0x7F000000) 262 | (last ? AHD_DMA_LAST_SEG : 0)); 263 return (sg + 1); 264 } 265} 266 267static __inline void 268ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) 269{ 270 /* XXX Handle target mode SCBs. */ 271 scb->crc_retry_count = 0; 272 if ((scb->flags & SCB_PACKETIZED) != 0) { 273 /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ 274 scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; 275 } else { 276 if (aic_get_transfer_length(scb) & 0x01) 277 scb->hscb->task_attribute = SCB_XFERLEN_ODD; 278 else 279 scb->hscb->task_attribute = 0; 280 } 281 282 if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR 283 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) 284 scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = 285 aic_htole32(scb->sense_busaddr); 286} 287 288static __inline void 289ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) 290{ 291 /* 292 * Copy the first SG into the "current" data ponter area. 293 */ 294 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { 295 struct ahd_dma64_seg *sg; 296 297 sg = (struct ahd_dma64_seg *)scb->sg_list; 298 scb->hscb->dataptr = sg->addr; 299 scb->hscb->datacnt = sg->len; 300 } else { 301 struct ahd_dma_seg *sg; 302 uint32_t *dataptr_words; 303 304 sg = (struct ahd_dma_seg *)scb->sg_list; 305 dataptr_words = (uint32_t*)&scb->hscb->dataptr; 306 dataptr_words[0] = sg->addr; 307 dataptr_words[1] = 0; 308 if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { 309 uint64_t high_addr; 310 311 high_addr = aic_le32toh(sg->len) & 0x7F000000; 312 scb->hscb->dataptr |= aic_htole64(high_addr << 8); 313 } 314 scb->hscb->datacnt = sg->len; 315 } 316 /* 317 * Note where to find the SG entries in bus space. 318 * We also set the full residual flag which the 319 * sequencer will clear as soon as a data transfer 320 * occurs. 321 */ 322 scb->hscb->sgptr = aic_htole32(scb->sg_list_busaddr|SG_FULL_RESID); 323} 324 325static __inline void 326ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) 327{ 328 scb->hscb->sgptr = aic_htole32(SG_LIST_NULL); 329 scb->hscb->dataptr = 0; 330 scb->hscb->datacnt = 0; 331} 332 333/************************** Memory mapping routines ***************************/ 334static __inline size_t ahd_sg_size(struct ahd_softc *ahd); 335static __inline void * 336 ahd_sg_bus_to_virt(struct ahd_softc *ahd, 337 struct scb *scb, 338 uint32_t sg_busaddr); 339static __inline uint32_t 340 ahd_sg_virt_to_bus(struct ahd_softc *ahd, 341 struct scb *scb, 342 void *sg); 343static __inline void ahd_sync_scb(struct ahd_softc *ahd, 344 struct scb *scb, int op); 345static __inline void ahd_sync_sglist(struct ahd_softc *ahd, 346 struct scb *scb, int op); 347static __inline void ahd_sync_sense(struct ahd_softc *ahd, 348 struct scb *scb, int op); 349static __inline uint32_t 350 ahd_targetcmd_offset(struct ahd_softc *ahd, 351 u_int index); 352 353static __inline size_t 354ahd_sg_size(struct ahd_softc *ahd) 355{ 356 if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) 357 return (sizeof(struct ahd_dma64_seg)); 358 return (sizeof(struct ahd_dma_seg)); 359} 360 361static __inline void * 362ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) 363{ 364 bus_addr_t sg_offset; 365 366 /* sg_list_phys points to entry 1, not 0 */ 367 sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); 368 return ((uint8_t *)scb->sg_list + sg_offset); 369} 370 371static __inline uint32_t 372ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) 373{ 374 bus_addr_t sg_offset; 375 376 /* sg_list_phys points to entry 1, not 0 */ 377 sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) 378 - ahd_sg_size(ahd); 379 380 return (scb->sg_list_busaddr + sg_offset); 381} 382 383static __inline void 384ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) 385{ 386 aic_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, 387 scb->hscb_map->dmamap, 388 /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, 389 /*len*/sizeof(*scb->hscb), op); 390} 391 392static __inline void 393ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) 394{ 395 if (scb->sg_count == 0) 396 return; 397 398 aic_dmamap_sync(ahd, ahd->scb_data.sg_dmat, 399 scb->sg_map->dmamap, 400 /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), 401 /*len*/ahd_sg_size(ahd) * scb->sg_count, op); 402} 403 404static __inline void 405ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) 406{ 407 aic_dmamap_sync(ahd, ahd->scb_data.sense_dmat, 408 scb->sense_map->dmamap, 409 /*offset*/scb->sense_busaddr, 410 /*len*/AHD_SENSE_BUFSIZE, op); 411} 412 413static __inline uint32_t 414ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) 415{ 416 return (((uint8_t *)&ahd->targetcmds[index]) 417 - (uint8_t *)ahd->qoutfifo); 418} 419 420/********************** Miscellaneous Support Functions ***********************/ 421static __inline void ahd_complete_scb(struct ahd_softc *ahd, 422 struct scb *scb); 423static __inline void ahd_update_residual(struct ahd_softc *ahd, 424 struct scb *scb); 425static __inline struct ahd_initiator_tinfo * 426 ahd_fetch_transinfo(struct ahd_softc *ahd, 427 char channel, u_int our_id, 428 u_int remote_id, 429 struct ahd_tmode_tstate **tstate); 430static __inline uint16_t 431 ahd_inw(struct ahd_softc *ahd, u_int port); 432static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, 433 u_int value); 434static __inline uint32_t 435 ahd_inl(struct ahd_softc *ahd, u_int port); 436static __inline void ahd_outl(struct ahd_softc *ahd, u_int port, 437 uint32_t value); 438static __inline uint64_t 439 ahd_inq(struct ahd_softc *ahd, u_int port); 440static __inline void ahd_outq(struct ahd_softc *ahd, u_int port, 441 uint64_t value); 442static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd); 443static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); 444static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd); 445static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value); 446static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd); 447static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value); 448static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd); 449static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value); 450static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd); 451static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value); 452static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd); 453static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value); 454static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); 455static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); 456static __inline uint32_t 457 ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); 458static __inline uint64_t 459 ahd_inq_scbram(struct ahd_softc *ahd, u_int offset); 460static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, 461 struct scb *scb); 462static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); 463static __inline uint8_t * 464 ahd_get_sense_buf(struct ahd_softc *ahd, 465 struct scb *scb); 466static __inline uint32_t 467 ahd_get_sense_bufaddr(struct ahd_softc *ahd, 468 struct scb *scb); 469 470static __inline void 471ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) 472{ 473 uint32_t sgptr; 474 475 sgptr = aic_le32toh(scb->hscb->sgptr); 476 if ((sgptr & SG_STATUS_VALID) != 0) 477 ahd_handle_scb_status(ahd, scb); 478 else 479 ahd_done(ahd, scb); 480} 481 482/* 483 * Determine whether the sequencer reported a residual 484 * for this SCB/transaction. 485 */ 486static __inline void 487ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) 488{ 489 uint32_t sgptr; 490 491 sgptr = aic_le32toh(scb->hscb->sgptr); 492 if ((sgptr & SG_STATUS_VALID) != 0) 493 ahd_calc_residual(ahd, scb); 494} 495 496/* 497 * Return pointers to the transfer negotiation information 498 * for the specified our_id/remote_id pair. 499 */ 500static __inline struct ahd_initiator_tinfo * 501ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, 502 u_int remote_id, struct ahd_tmode_tstate **tstate) 503{ 504 /* 505 * Transfer data structures are stored from the perspective 506 * of the target role. Since the parameters for a connection 507 * in the initiator role to a given target are the same as 508 * when the roles are reversed, we pretend we are the target. 509 */ 510 if (channel == 'B') 511 our_id += 8; 512 *tstate = ahd->enabled_targets[our_id]; 513 return (&(*tstate)->transinfo[remote_id]); 514} 515 516#define AHD_COPY_COL_IDX(dst, src) \ 517do { \ 518 dst->hscb->scsiid = src->hscb->scsiid; \ 519 dst->hscb->lun = src->hscb->lun; \ 520} while (0) 521 522static __inline uint16_t 523ahd_inw(struct ahd_softc *ahd, u_int port) 524{ 525 /* 526 * Read high byte first as some registers increment 527 * or have other side effects when the low byte is 528 * read. 529 */ 530 return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); 531} 532 533static __inline void 534ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) 535{ 536 /* 537 * Write low byte first to accommodate registers 538 * such as PRGMCNT where the order maters. 539 */ 540 ahd_outb(ahd, port, value & 0xFF); 541 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 542} 543 544static __inline uint32_t 545ahd_inl(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} 552 553static __inline void 554ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) 555{ 556 ahd_outb(ahd, port, (value) & 0xFF); 557 ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); 558 ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); 559 ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); 560} 561 562static __inline uint64_t 563ahd_inq(struct ahd_softc *ahd, u_int port) 564{ 565 return ((ahd_inb(ahd, port)) 566 | (ahd_inb(ahd, port+1) << 8) 567 | (ahd_inb(ahd, port+2) << 16) 568 | (ahd_inb(ahd, port+3) << 24) 569 | (((uint64_t)ahd_inb(ahd, port+4)) << 32) 570 | (((uint64_t)ahd_inb(ahd, port+5)) << 40) 571 | (((uint64_t)ahd_inb(ahd, port+6)) << 48) 572 | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); 573} 574 575static __inline void 576ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) 577{ 578 ahd_outb(ahd, port, value & 0xFF); 579 ahd_outb(ahd, port+1, (value >> 8) & 0xFF); 580 ahd_outb(ahd, port+2, (value >> 16) & 0xFF); 581 ahd_outb(ahd, port+3, (value >> 24) & 0xFF); 582 ahd_outb(ahd, port+4, (value >> 32) & 0xFF); 583 ahd_outb(ahd, port+5, (value >> 40) & 0xFF); 584 ahd_outb(ahd, port+6, (value >> 48) & 0xFF); 585 ahd_outb(ahd, port+7, (value >> 56) & 0xFF); 586} 587 588static __inline u_int 589ahd_get_scbptr(struct ahd_softc *ahd) 590{ 591 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 592 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 593 return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); 594} 595 596static __inline void 597ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) 598{ 599 AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), 600 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); 601 ahd_outb(ahd, SCBPTR, scbptr & 0xFF); 602 ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); 603} 604 605static __inline u_int 606ahd_get_hnscb_qoff(struct ahd_softc *ahd) 607{ 608 return (ahd_inw_atomic(ahd, HNSCB_QOFF)); 609} 610 611static __inline void 612ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) 613{ 614 ahd_outw_atomic(ahd, HNSCB_QOFF, value); 615} 616 617static __inline u_int 618ahd_get_hescb_qoff(struct ahd_softc *ahd) 619{ 620 return (ahd_inb(ahd, HESCB_QOFF)); 621} 622 623static __inline void 624ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) 625{ 626 ahd_outb(ahd, HESCB_QOFF, value); 627} 628 629static __inline u_int 630ahd_get_snscb_qoff(struct ahd_softc *ahd) 631{ 632 u_int oldvalue; 633 634 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 635 oldvalue = ahd_inw(ahd, SNSCB_QOFF); 636 ahd_outw(ahd, SNSCB_QOFF, oldvalue); 637 return (oldvalue); 638} 639 640static __inline void 641ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) 642{ 643 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 644 ahd_outw(ahd, SNSCB_QOFF, value); 645} 646 647static __inline u_int 648ahd_get_sescb_qoff(struct ahd_softc *ahd) 649{ 650 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 651 return (ahd_inb(ahd, SESCB_QOFF)); 652} 653 654static __inline void 655ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) 656{ 657 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 658 ahd_outb(ahd, SESCB_QOFF, value); 659} 660 661static __inline u_int 662ahd_get_sdscb_qoff(struct ahd_softc *ahd) 663{ 664 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 665 return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); 666} 667 668static __inline void 669ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) 670{ 671 AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); 672 ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); 673 ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); 674} 675 676static __inline u_int 677ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) 678{ 679 u_int value; 680 681 /* 682 * Workaround PCI-X Rev A. hardware bug. 683 * After a host read of SCB memory, the chip 684 * may become confused into thinking prefetch 685 * was required. This starts the discard timer 686 * running and can cause an unexpected discard 687 * timer interrupt. The work around is to read 688 * a normal register prior to the exhaustion of 689 * the discard timer. The mode pointer register 690 * has no side effects and so serves well for 691 * this purpose. 692 * 693 * Razor #528 694 */ 695 value = ahd_inb(ahd, offset); 696 if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0) 697 ahd_inb(ahd, MODE_PTR); 698 return (value); 699} 700 701static __inline u_int 702ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) 703{ 704 return (ahd_inb_scbram(ahd, offset) 705 | (ahd_inb_scbram(ahd, offset+1) << 8)); 706} 707 708static __inline uint32_t 709ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) 710{ 711 return (ahd_inw_scbram(ahd, offset) 712 | (ahd_inw_scbram(ahd, offset+2) << 16)); 713} 714 715static __inline uint64_t 716ahd_inq_scbram(struct ahd_softc *ahd, u_int offset) 717{ 718 return (ahd_inl_scbram(ahd, offset) 719 | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32); 720} 721 722static __inline struct scb * 723ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) 724{ 725 struct scb* scb; 726 727 if (tag >= AHD_SCB_MAX) 728 return (NULL); 729 scb = ahd->scb_data.scbindex[tag]; 730 if (scb != NULL) 731 ahd_sync_scb(ahd, scb, 732 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 733 return (scb); 734} 735 736static __inline void 737ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) 738{ 739 struct hardware_scb *q_hscb; 740 struct map_node *q_hscb_map; 741 uint32_t saved_hscb_busaddr; 742 743 /* 744 * Our queuing method is a bit tricky. The card 745 * knows in advance which HSCB (by address) to download, 746 * and we can't disappoint it. To achieve this, the next 747 * HSCB to download is saved off in ahd->next_queued_hscb. 748 * When we are called to queue "an arbitrary scb", 749 * we copy the contents of the incoming HSCB to the one 750 * the sequencer knows about, swap HSCB pointers and 751 * finally assign the SCB to the tag indexed location 752 * in the scb_array. This makes sure that we can still 753 * locate the correct SCB by SCB_TAG. 754 */ 755 q_hscb = ahd->next_queued_hscb; 756 q_hscb_map = ahd->next_queued_hscb_map; 757 saved_hscb_busaddr = q_hscb->hscb_busaddr; 758 memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); 759 q_hscb->hscb_busaddr = saved_hscb_busaddr; 760 q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; 761 762 /* Now swap HSCB pointers. */ 763 ahd->next_queued_hscb = scb->hscb; 764 ahd->next_queued_hscb_map = scb->hscb_map; 765 scb->hscb = q_hscb; 766 scb->hscb_map = q_hscb_map; 767 768 /* Now define the mapping from tag to SCB in the scbindex */ 769 ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; 770} 771 772/* 773 * Tell the sequencer about a new transaction to execute. 774 */ 775static __inline void 776ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) 777{ 778 ahd_swap_with_next_hscb(ahd, scb); 779 780 if (SCBID_IS_NULL(SCB_GET_TAG(scb))) 781 panic("Attempt to queue invalid SCB tag %x\n", 782 SCB_GET_TAG(scb)); 783 784 /* 785 * Keep a history of SCBs we've downloaded in the qinfifo. 786 */ 787 ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); 788 ahd->qinfifonext++; 789 790 if (scb->sg_count != 0) 791 ahd_setup_data_scb(ahd, scb); 792 else 793 ahd_setup_noxfer_scb(ahd, scb); 794 ahd_setup_scb_common(ahd, scb); 795 796 /* 797 * Make sure our data is consistent from the 798 * perspective of the adapter. 799 */ 800 ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 801 802#ifdef AHD_DEBUG 803 if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { 804 uint64_t host_dataptr; 805 806 host_dataptr = aic_le64toh(scb->hscb->dataptr); 807 printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n", 808 ahd_name(ahd), 809 SCB_GET_TAG(scb), scb->hscb->scsiid, 810 aic_le32toh(scb->hscb->hscb_busaddr), 811 (u_int)((host_dataptr >> 32) & 0xFFFFFFFF), 812 (u_int)(host_dataptr & 0xFFFFFFFF), 813 aic_le32toh(scb->hscb->datacnt)); 814 } 815#endif 816 /* Tell the adapter about the newly queued SCB */ 817 ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); 818} 819 820static __inline uint8_t * 821ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) 822{ 823 return (scb->sense_data); 824} 825 826static __inline uint32_t 827ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) 828{ 829 return (scb->sense_busaddr); 830} 831 832/************************** Interrupt Processing ******************************/ 833static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op); 834static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op); 835static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd); 836static __inline int ahd_intr(struct ahd_softc *ahd); 837 838static __inline void 839ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) 840{ 841 aic_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 842 /*offset*/0, 843 /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op); 844} 845 846static __inline void 847ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) 848{ 849#ifdef AHD_TARGET_MODE 850 if ((ahd->flags & AHD_TARGETROLE) != 0) { 851 aic_dmamap_sync(ahd, ahd->shared_data_dmat, 852 ahd->shared_data_map.dmamap, 853 ahd_targetcmd_offset(ahd, 0), 854 sizeof(struct target_cmd) * AHD_TMODE_CMDS, 855 op); 856 } 857#endif 858} 859 860/* 861 * See if the firmware has posted any completed commands 862 * into our in-core command complete fifos. 863 */ 864#define AHD_RUN_QOUTFIFO 0x1 865#define AHD_RUN_TQINFIFO 0x2 866static __inline u_int 867ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) 868{ 869 u_int retval; 870 871 retval = 0; 872 aic_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, 873 /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo), 874 /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD); 875 if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag 876 == ahd->qoutfifonext_valid_tag) 877 retval |= AHD_RUN_QOUTFIFO; 878#ifdef AHD_TARGET_MODE 879 if ((ahd->flags & AHD_TARGETROLE) != 0 880 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { 881 aic_dmamap_sync(ahd, ahd->shared_data_dmat, 882 ahd->shared_data_map.dmamap, 883 ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), 884 /*len*/sizeof(struct target_cmd), 885 BUS_DMASYNC_POSTREAD); 886 if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) 887 retval |= AHD_RUN_TQINFIFO; 888 } 889#endif 890 return (retval); 891} 892 893/* 894 * Catch an interrupt from the adapter 895 */ 896static __inline int 897ahd_intr(struct ahd_softc *ahd) 898{ 899 u_int intstat; 900 901 if ((ahd->pause & INTEN) == 0) { 902 /* 903 * Our interrupt is not enabled on the chip 904 * and may be disabled for re-entrancy reasons, 905 * so just return. This is likely just a shared 906 * interrupt. 907 */ 908 return (0); 909 } 910 911 /* 912 * Instead of directly reading the interrupt status register, 913 * infer the cause of the interrupt by checking our in-core 914 * completion queues. This avoids a costly PCI bus read in 915 * most cases. 916 */ 917 if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 918 && (ahd_check_cmdcmpltqueues(ahd) != 0)) 919 intstat = CMDCMPLT; 920 else 921 intstat = ahd_inb(ahd, INTSTAT); 922 923 if ((intstat & INT_PEND) == 0) 924 return (0); 925 926 if (intstat & CMDCMPLT) { 927 ahd_outb(ahd, CLRINT, CLRCMDINT); 928 929 /* 930 * Ensure that the chip sees that we've cleared 931 * this interrupt before we walk the output fifo. 932 * Otherwise, we may, due to posted bus writes, 933 * clear the interrupt after we finish the scan, 934 * and after the sequencer has added new entries 935 * and asserted the interrupt again. 936 */ 937 if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { 938 if (ahd_is_paused(ahd)) { 939 /* 940 * Potentially lost SEQINT. 941 * If SEQINTCODE is non-zero, 942 * simulate the SEQINT. 943 */ 944 if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT) 945 intstat |= SEQINT; 946 } 947 } else { 948 ahd_flush_device_writes(ahd); 949 } 950 ahd_run_qoutfifo(ahd); 951 ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++; 952 ahd->cmdcmplt_total++; 953#ifdef AHD_TARGET_MODE 954 if ((ahd->flags & AHD_TARGETROLE) != 0) 955 ahd_run_tqinfifo(ahd, /*paused*/FALSE); 956#endif 957 } 958 959 /* 960 * Handle statuses that may invalidate our cached 961 * copy of INTSTAT separately. 962 */ 963 if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) { 964 /* Hot eject. Do nothing */ 965 } else if (intstat & HWERRINT) { 966 ahd_handle_hwerrint(ahd); 967 } else if ((intstat & (PCIINT|SPLTINT)) != 0) { 968 ahd->bus_intr(ahd); 969 } else { 970 971 if ((intstat & SEQINT) != 0) 972 ahd_handle_seqint(ahd, intstat); 973 974 if ((intstat & SCSIINT) != 0) 975 ahd_handle_scsiint(ahd, intstat); 976 } 977 return (1); 978} 979 980#endif /* _AIC79XX_INLINE_H_ */ 981