static int ld_twa_dobio(struct ld_twa_softc *sc, void *data, size_t datasize, daddr_t blkno, struct buf *bp) { int rv; struct twa_request *tr; struct twa_softc *twa; twa = device_private(device_parent(sc->sc_ld.sc_dv)); if ((tr = twa_get_request(twa, 0)) == NULL) { return (EAGAIN); } if (bp->b_flags & B_READ) { tr->tr_flags = TWA_CMD_DATA_OUT; } else { tr->tr_flags = TWA_CMD_DATA_IN; } tr->tr_data = data; tr->tr_length = datasize; tr->tr_cmd_pkt_type = (TWA_CMD_PKT_TYPE_9K | TWA_CMD_PKT_TYPE_EXTERNAL); tr->tr_command->cmd_hdr.header_desc.size_header = 128; tr->tr_command->command.cmd_pkt_9k.command.opcode = TWA_OP_EXECUTE_SCSI_COMMAND; tr->tr_command->command.cmd_pkt_9k.unit = sc->sc_hwunit; tr->tr_command->command.cmd_pkt_9k.request_id = tr->tr_request_id; tr->tr_command->command.cmd_pkt_9k.status = 0; tr->tr_command->command.cmd_pkt_9k.sgl_entries = 1; tr->tr_command->command.cmd_pkt_9k.sgl_offset = 16; /* offset from end of hdr = max cdb len */ ld_twa_scsicmd(sc, tr, bp); tr->tr_callback = ld_twa_handler; tr->tr_ld_sc = sc; tr->bp = bp; rv = twa_map_request(tr); return (rv); }
static int ld_twa_flush(struct ld_softc *ld, int flags) { int s, rv = 0; struct twa_request *tr; struct twa_softc *twa = device_private(device_parent(ld->sc_dv)); struct ld_twa_softc *sc = (void *)ld; struct twa_command_generic *generic_cmd; /* Get a request packet. */ tr = twa_get_request_wait(twa, 0); KASSERT(tr != NULL); tr->tr_cmd_pkt_type = (TWA_CMD_PKT_TYPE_9K | TWA_CMD_PKT_TYPE_EXTERNAL); tr->tr_callback = twa_request_wait_handler; tr->tr_ld_sc = sc; tr->tr_command->cmd_hdr.header_desc.size_header = 128; generic_cmd = &(tr->tr_command->command.cmd_pkt_7k.generic); generic_cmd->opcode = TWA_OP_FLUSH; generic_cmd->size = 2; generic_cmd->unit = sc->sc_hwunit; generic_cmd->request_id = tr->tr_request_id; generic_cmd->sgl_offset = 0; generic_cmd->host_id = 0; generic_cmd->status = 0; generic_cmd->flags = 0; generic_cmd->count = 0; rv = twa_map_request(tr); s = splbio(); while (tr->tr_status != TWA_CMD_COMPLETE) if ((rv = tsleep(tr, PRIBIO, "twaflush", 60 * hz)) != 0) break; twa_release_request(tr); splx(s); return (rv); }
/* * Function name: twa_execute_scsi * Description: Build a fw cmd, based on a CAM style ccb, and * send it down. * * Input: tr -- ptr to request pkt * ccb -- ptr to CAM style ccb * Output: None * Return value: 0 -- success * non-zero-- failure */ int twa_execute_scsi(struct twa_request *tr, union ccb *ccb) { struct twa_softc *sc = tr->tr_sc; struct twa_command_packet *cmdpkt; struct twa_command_9k *cmd9k; struct ccb_hdr *ccb_h = &(ccb->ccb_h); struct ccb_scsiio *csio = &(ccb->csio); int error; twa_dbg_dprint(3, sc, "SCSI I/O request 0x%x", csio->cdb_io.cdb_bytes[0]); if (ccb_h->target_id >= TWA_MAX_UNITS) { twa_dbg_dprint(3, sc, "Invalid target. PTL = %x %x %x", ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun); ccb_h->status |= CAM_TID_INVALID; if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) xpt_done(ccb); return(1); } if (ccb_h->target_lun != 0) { twa_dbg_dprint(3, sc, "Invalid lun. PTL = %x %x %x", ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun); ccb_h->status |= CAM_LUN_INVALID; if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) xpt_done(ccb); return(1); } if(ccb_h->flags & CAM_CDB_PHYS) { twa_printf(sc, "Physical CDB address!\n"); ccb_h->status = CAM_REQ_CMP_ERR; if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) xpt_done(ccb); return(1); } /* * We are going to work on this request. Mark it as enqueued (though * we don't actually queue it...) */ ccb_h->status |= CAM_SIM_QUEUED; if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { if(ccb_h->flags & CAM_DIR_IN) tr->tr_flags |= TWA_CMD_DATA_IN; else tr->tr_flags |= TWA_CMD_DATA_OUT; } cmdpkt = tr->tr_command; cmdpkt->cmd_hdr.header_desc.size_header = 128; cmd9k = &(cmdpkt->command.cmd_pkt_9k); cmd9k->command.opcode = TWA_OP_EXECUTE_SCSI_COMMAND; cmd9k->unit = ccb_h->target_id; cmd9k->request_id = tr->tr_request_id; cmd9k->status = 0; cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */ if(ccb_h->flags & CAM_CDB_POINTER) bcopy(csio->cdb_io.cdb_ptr, cmd9k->cdb, csio->cdb_len); else bcopy(csio->cdb_io.cdb_bytes, cmd9k->cdb, csio->cdb_len); if (!(ccb_h->flags & CAM_DATA_PHYS)) { /* Virtual data addresses. Need to convert them... */ twa_dbg_dprint(3, sc, "XPT_SCSI_IO: Single virtual address!"); if (!(ccb_h->flags & CAM_SCATTER_VALID)) { if (csio->dxfer_len > TWA_MAX_IO_SIZE) { twa_printf(sc, "I/O size %d too big.\n", csio->dxfer_len); ccb_h->status = CAM_REQ_TOO_BIG; if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) xpt_done(ccb); return(1); } if ((tr->tr_length = csio->dxfer_len)) { tr->tr_data = csio->data_ptr; cmd9k->sgl_entries = 1; } } else { twa_printf(sc, "twa_execute_scsi: XPT_SCSI_IO: Got SGList!\n"); ccb_h->status = CAM_REQ_CMP_ERR; if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) { xpt_done(ccb); } return(1); } } else { /* Data addresses are physical. */ twa_printf(sc, "twa_execute_scsi: XPT_SCSI_IO: Physical data addresses!\n"); ccb_h->status = CAM_REQ_CMP_ERR; if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) { ccb_h->status |= CAM_RELEASE_SIMQ; ccb_h->status &= ~CAM_SIM_QUEUED; xpt_done(ccb); } return(1); } tr->tr_cmd_pkt_type |= TWA_CMD_PKT_TYPE_9K; /* twa_setup_data_dmamap will fill in the SGL, and submit the I/O. */ error = twa_map_request(tr); return(error); }