📄 bt.c
字号:
} else { bt->max_ccbs = 30; if (bt->firmware_ver[0] == '3' && (strcmp(bt->firmware_ver, "3.35") >= 0)) bt->tag_capable = TRUE; else bt->tag_capable = FALSE; } if (bt->tag_capable != FALSE) bt->tags_permitted = ALL_TARGETS; /* Determine Sync/Wide/Disc settings */ if (bt->firmware_ver[0] >= '4') { auto_scsi_data_t auto_scsi_data; fetch_lram_params_t fetch_lram_params; int error; /* * These settings are stored in the * AutoSCSI data in LRAM of 'W' and 'C' * adapters. */ fetch_lram_params.offset = AUTO_SCSI_BYTE_OFFSET; fetch_lram_params.response_len = sizeof(auto_scsi_data); error = bt_cmd(bt, BOP_FETCH_LRAM, (u_int8_t*)&fetch_lram_params, sizeof(fetch_lram_params), (u_int8_t*)&auto_scsi_data, sizeof(auto_scsi_data), DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed " "Get Auto SCSI Info\n", bt_name(bt)); return (error); } bt->disc_permitted = auto_scsi_data.low_disc_permitted | (auto_scsi_data.high_disc_permitted << 8); bt->sync_permitted = auto_scsi_data.low_sync_permitted | (auto_scsi_data.high_sync_permitted << 8); bt->fast_permitted = auto_scsi_data.low_fast_permitted | (auto_scsi_data.high_fast_permitted << 8); bt->ultra_permitted = auto_scsi_data.low_ultra_permitted | (auto_scsi_data.high_ultra_permitted << 8); bt->wide_permitted = auto_scsi_data.low_wide_permitted | (auto_scsi_data.high_wide_permitted << 8); if (bt->ultra_scsi == FALSE) bt->ultra_permitted = 0; if (bt->wide_bus == FALSE) bt->wide_permitted = 0; } else { /* * 'S' and 'A' series have this information in the setup * information structure. */ setup_data_t setup_info; length_param = sizeof(setup_info); error = bt_cmd(bt, BOP_INQUIRE_SETUP_INFO, &length_param, /*paramlen*/1, (u_int8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed " "Get Setup Info\n", bt_name(bt)); return (error); } if (setup_info.initiate_sync != 0) { bt->sync_permitted = ALL_TARGETS; if (bt->model[0] == '7') { if (esetup_info.sync_neg10MB != 0) bt->fast_permitted = ALL_TARGETS; if (strcmp(bt->model, "757") == 0) bt->wide_permitted = ALL_TARGETS; } } bt->disc_permitted = ALL_TARGETS; } /* We need as many mailboxes as we can have ccbs */ bt->num_boxes = bt->max_ccbs; /* Determine our SCSI ID */ error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, (u_int8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed Get Config\n", bt_name(bt)); return (error); } bt->scsi_id = config_data.scsi_id; return (0);}/* * Start the board, ready for normal operation */intbt_init(struct bt_softc* bt){ /* Announce the Adapter */ printf("%s: BT-%s FW Rev. %s ", bt_name(bt), bt->model, bt->firmware_ver); if (bt->ultra_scsi != 0) printf("Ultra "); if (bt->wide_bus != 0) printf("Wide "); else printf("Narrow "); if (bt->diff_bus != 0) printf("Diff "); printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", bt->scsi_id, bt->max_ccbs); /* * Create our DMA tags. These tags define the kinds of device * accessable memory allocations and memory mappings we will * need to perform during normal operation. * * Unless we need to further restrict the allocation, we rely * on the restrictions of the parent dmat, hence the common * use of MAXADDR and MAXSIZE. */ /* DMA tag for mapping buffers into device visible space. */ if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/MAXBSIZE, /*nsegments*/BT_NSEG, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/BUS_DMA_ALLOCNOW, &bt->buffer_dmat) != 0) { goto error_exit; } bt->init_level++; /* DMA tag for our mailboxes */ if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, bt->num_boxes * (sizeof(bt_mbox_in_t) + sizeof(bt_mbox_out_t)), /*nsegments*/1, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, &bt->mailbox_dmat) != 0) { goto error_exit; } bt->init_level++; /* Allocation for our mailboxes */ if (bus_dmamem_alloc(bt->mailbox_dmat, (void **)&bt->out_boxes, BUS_DMA_NOWAIT, &bt->mailbox_dmamap) != 0) { goto error_exit; } bt->init_level++; /* And permanently map them */ bus_dmamap_load(bt->mailbox_dmat, bt->mailbox_dmamap, bt->out_boxes, bt->num_boxes * (sizeof(bt_mbox_in_t) + sizeof(bt_mbox_out_t)), btmapmboxes, bt, /*flags*/0); bt->init_level++; bt->in_boxes = (bt_mbox_in_t *)&bt->out_boxes[bt->num_boxes]; btinitmboxes(bt); /* DMA tag for our ccb structures */ if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, bt->max_ccbs * sizeof(struct bt_ccb), /*nsegments*/1, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, &bt->ccb_dmat) != 0) { goto error_exit; } bt->init_level++; /* Allocation for our ccbs */ if (bus_dmamem_alloc(bt->ccb_dmat, (void **)&bt->bt_ccb_array, BUS_DMA_NOWAIT, &bt->ccb_dmamap) != 0) { goto error_exit; } bt->init_level++; /* And permanently map them */ bus_dmamap_load(bt->ccb_dmat, bt->ccb_dmamap, bt->bt_ccb_array, bt->max_ccbs * sizeof(struct bt_ccb), btmapccbs, bt, /*flags*/0); bt->init_level++; /* DMA tag for our S/G structures. We allocate in page sized chunks */ if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, PAGE_SIZE, /*nsegments*/1, /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, /*flags*/0, &bt->sg_dmat) != 0) { goto error_exit; } bt->init_level++; /* Perform initial CCB allocation */ bzero(bt->bt_ccb_array, bt->max_ccbs * sizeof(struct bt_ccb)); btallocccbs(bt); if (bt->num_ccbs == 0) { printf("%s: bt_init - Unable to allocate initial ccbs\n", bt_name(bt)); goto error_exit; } /* * Note that we are going and return (to probe) */ return 0;error_exit: return (ENXIO);}intbt_attach(struct bt_softc *bt){ int tagged_dev_openings; struct cam_devq *devq; /* * We reserve 1 ccb for error recovery, so don't * tell the XPT about it. */ if (bt->tag_capable != 0) tagged_dev_openings = bt->max_ccbs - 1; else tagged_dev_openings = 0; /* * Create the device queue for our SIM. */ devq = cam_simq_alloc(bt->max_ccbs - 1); if (devq == NULL) return (ENOMEM); /* * Construct our SIM entry */ bt->sim = cam_sim_alloc(btaction, btpoll, "bt", bt, bt->unit, 2, tagged_dev_openings, devq); if (bt->sim == NULL) { cam_simq_free(devq); return (ENOMEM); } if (xpt_bus_register(bt->sim, 0) != CAM_SUCCESS) { cam_sim_free(bt->sim, /*free_devq*/TRUE); return (ENXIO); } if (xpt_create_path(&bt->path, /*periph*/NULL, cam_sim_path(bt->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { xpt_bus_deregister(cam_sim_path(bt->sim)); cam_sim_free(bt->sim, /*free_devq*/TRUE); return (ENXIO); } return (0);}char *bt_name(struct bt_softc *bt){ static char name[10]; snprintf(name, sizeof(name), "bt%d", bt->unit); return (name);}intbt_check_probed_iop(u_int ioport){ u_int i; for (i = 0; i < BT_NUM_ISAPORTS; i++) { if (bt_isa_ports[i].addr == ioport) { if (bt_isa_ports[i].probed != 0) return (1); else { return (0); } } } return (1);}voidbt_mark_probed_bio(isa_compat_io_t port){ if (port < BIO_DISABLED) bt_mark_probed_iop(bt_board_ports[port]);}voidbt_mark_probed_iop(u_int ioport){ u_int i; for (i = 0; i < BT_NUM_ISAPORTS; i++) { if (ioport == bt_isa_ports[i].addr) { bt_isa_ports[i].probed = 1; break; } }}voidbt_find_probe_range(int ioport, int *port_index, int *max_port_index){ if (ioport > 0) { int i; for (i = 0;i < BT_NUM_ISAPORTS; i++) if (ioport <= bt_isa_ports[i].addr) break; if ((i >= BT_NUM_ISAPORTS) || (ioport != bt_isa_ports[i].addr)) { printf("bt_isa_probe: Invalid baseport of 0x%x specified.bt_isa_probe: Nearest valid baseport is 0x%x.bt_isa_probe: Failing probe.\n", ioport, (i < BT_NUM_ISAPORTS) ? bt_isa_ports[i].addr : bt_isa_ports[BT_NUM_ISAPORTS - 1].addr); *port_index = *max_port_index = -1; return; } *port_index = *max_port_index = bt_isa_ports[i].bio; } else { *port_index = 0; *max_port_index = BT_NUM_ISAPORTS - 1; }}intbt_iop_from_bio(isa_compat_io_t bio_index){ if (bio_index >= 0 && bio_index < BT_NUM_ISAPORTS) return (bt_board_ports[bio_index]); return (-1);}static voidbtallocccbs(struct bt_softc *bt){ struct bt_ccb *next_ccb; struct sg_map_node *sg_map; bus_addr_t physaddr; bt_sg_t *segs; int newcount; int i; next_ccb = &bt->bt_ccb_array[bt->num_ccbs]; sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); if (sg_map == NULL) return; /* Allocate S/G space for the next batch of CCBS */ if (bus_dmamem_alloc(bt->sg_dmat, (void **)&sg_map->sg_vaddr, BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { free(sg_map, M_DEVBUF); return; } SLIST_INSERT_HEAD(&bt->sg_maps, sg_map, links); bus_dmamap_load(bt->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, PAGE_SIZE, btmapsgs, bt, /*flags*/0); segs = sg_map->sg_vaddr; physaddr = sg_map->sg_physaddr; newcount = (PAGE_SIZE / (BT_NSEG * sizeof(bt_sg_t))); for (i = 0; bt->num_ccbs < bt->max_ccbs && i < newcount; i++) { int error; next_ccb->sg_list = segs; next_ccb->sg_list_phys = physaddr; next_ccb->flags = BCCB_FREE; error = bus_dmamap_create(bt->buffer_dmat, /*flags*/0, &next_ccb->dmamap); if (error != 0) break; SLIST_INSERT_HEAD(&bt->free_bt_ccbs, next_ccb, links); segs += BT_NSEG; physaddr += (BT_NSEG * sizeof(bt_sg_t)); next_ccb++; bt->num_ccbs++; } /* Reserve a CCB for error recovery */ if (bt->recovery_bccb == NULL) { bt->recovery_bccb = SLIST_FIRST(&bt->free_bt_ccbs); SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); }}static __inline voidbtfreeccb(struct bt_softc *bt, struct bt_ccb *bccb){ int s; s = splcam(); if ((bccb->flags & BCCB_ACTIVE) != 0) LIST_REMOVE(&bccb->ccb->ccb_h, sim_links.le); if (bt->resource_shortage != 0 && (bccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { bccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; bt->resource_shortage = FALSE; } bccb->flags = BCCB_FREE; SLIST_INSERT_HEAD(&bt->free_bt_ccbs, bccb, links); bt->active_ccbs--; splx(s);}static __inline struct bt_ccb*btgetccb(struct bt_softc *bt){ struct bt_ccb* bccb; int s; s = splcam(); if ((bccb = SLIST_FIRST(&bt->free_bt_ccbs)) != NULL) { SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); bt->active_ccbs++; } else if (bt->num_ccbs < bt->max_ccbs) { btallocccbs(bt); bccb = SLIST_FIRST(&bt->free_bt_ccbs); if (bccb == NULL) printf("%s: Can't malloc BCCB\n", bt_name(bt)); else { SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); bt->active_ccbs++; } } splx(s); return (bccb);}static voidbtaction(struct cam_sim *sim, union ccb *ccb){ struct bt_softc *bt; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("btaction\n")); bt = (struct bt_softc *)cam_sim_softc(sim); switch (ccb->ccb_h.func_code) { /* Common cases first */ case XPT_SCSI_IO: /* Execute the requested I/O operation */ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { struct bt_ccb *bccb; struct bt_hccb *hccb; /* * get a bccb to use. */ if ((bccb = btgetccb(bt)) == NULL) { int s; s = splcam(); bt->resource_shortage = TRUE; splx(s); xpt_freeze_simq(bt->sim, /*count*/1); ccb->ccb_h.status = CAM_REQUEUE_REQ; xpt_done(ccb); return; } hccb = &bccb->hccb; /* * So we can find the BCCB when an abort is requested */ bccb->ccb = ccb; ccb->ccb_h.ccb_bccb_ptr = bccb; ccb->ccb_h.ccb_bt_ptr = bt; /* * Put all the arguments for the xfer in the bccb */ hccb->target_id = ccb->ccb_h.target_id; hccb->target_lun = ccb->ccb_h.target_lun; hccb->btstat = 0; hccb->sdstat = 0; if (ccb->ccb_h.func_code == XPT_SCSI_IO) { struct ccb_scsiio *csio; struct ccb_hdr *ccbh; csio = &ccb->csio; ccbh = &csio->ccb_h; hccb->opcode = INITIATOR_CCB_WRESID; hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) ? 1 : 0; hccb->dataout =(ccb->ccb_h.flags & CAM_DIR_OUT) ? 1 : 0; hccb->cmd_len = csio->cdb_len; if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { ccb->ccb_h.status = CAM_REQ_INVALID; btfreeccb(bt, bccb); xpt_done(ccb); return; } hccb->sense_len = csio->sense_len; if ((ccbh->flags & CAM_TAG_ACTION_VALID) != 0 && ccb->csio.tag_action != CAM_TAG_ACTION_NONE) { hccb->tag_enable = TRUE; hccb->tag_type = (ccb->csio.tag_action & 0x3); } else { hccb->tag_enable = FALSE; hccb->tag_type = 0; } if ((ccbh->flags & CAM_CDB_POINTER) != 0) { if ((ccbh->flags & CAM_CDB_PHYS) == 0) { bcopy(csio->cdb_io.cdb_ptr, hccb->scsi_cdb, hccb->cmd_len); } else { /* I guess I could map it in... */ ccbh->status = CAM_REQ_INVALID; btfreeccb(bt, bccb); xpt_done(ccb); return; } } else { bcopy(csio->cdb_io.cdb_bytes, hccb->scsi_cdb, hccb->cmd_len); } /* If need be, bounce our sense buffer */ if (bt->sense_buffers != NULL) { hccb->sense_addr = btsensepaddr(bt, bccb); } else { hccb->sense_addr = vtophys(&csio->sense_data); } /* * If we have any data to send with this command, * map it into bus space. */ /* Only use S/G if there is a transfer */ if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { /* * We've been given a pointer * to a single buffer. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -