static void wds_intr(struct wds *wp) { struct wds_req *rp; struct wds_mb *in; u_int8_t stat; u_int8_t c; int addr = wp->addr; DBG(DBX "wds%d: interrupt [\n", wp->unit); smallog('['); if (inb(addr + WDS_STAT) & WDS_IRQ) { c = inb(addr + WDS_IRQSTAT); if ((c & WDSI_MASK) == WDSI_MSVC) { c = c & ~WDSI_MASK; in = &wp->dx->imbs[c]; rp = cmdtovirt(wp, scsi_3btoul(in->addr)); stat = in->stat; if (rp != NULL) wds_done(wp, rp, stat); else device_printf(wp->dev, "got weird command address %p" "from controller\n", rp); in->stat = 0; } else device_printf(wp->dev, "weird interrupt, irqstat=0x%x\n", c); outb(addr + WDS_IRQACK, 0); } else { smallog('?'); } smallog(']'); DBG(DBX "wds%d: ]\n", wp->unit); }
/* * Convert the SCSI command in ccb to an ata_xfer command in xa * for ATA_PORT_T_DISK operations. Set the completion function * to convert the response back, then dispatch to the OpenBSD AHCI * layer. * * AHCI DISK commands only support a limited command set, and we * fake additional commands to make it play nice with the CAM subsystem. */ static void ahci_xpt_scsi_disk_io(struct ahci_port *ap, struct ata_port *atx, union ccb *ccb) { struct ccb_hdr *ccbh; struct ccb_scsiio *csio; struct ata_xfer *xa; struct ata_port *at; struct ata_fis_h2d *fis; struct ata_pass_12 *atp12; struct ata_pass_16 *atp16; scsi_cdb_t cdb; union scsi_data *rdata; int rdata_len; u_int64_t capacity; u_int64_t lba; u_int32_t count; ccbh = &ccb->csio.ccb_h; csio = &ccb->csio; at = atx ? atx : ap->ap_ata[0]; /* * XXX not passing NULL at for direct attach! */ xa = ahci_ata_get_xfer(ap, atx); rdata = (void *)csio->data_ptr; rdata_len = csio->dxfer_len; /* * Build the FIS or process the csio to completion. */ cdb = (void *)((ccbh->flags & CAM_CDB_POINTER) ? csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); switch(cdb->generic.opcode) { case REQUEST_SENSE: /* * Auto-sense everything, so explicit sense requests * return no-sense. */ ccbh->status = CAM_SCSI_STATUS_ERROR; break; case INQUIRY: /* * Inquiry supported features * * [opcode, byte2, page_code, length, control] */ if (cdb->inquiry.byte2 & SI_EVPD) { ahci_xpt_page_inquiry(ap, at, ccb); } else { bzero(rdata, rdata_len); if (rdata_len < SHORT_INQUIRY_LENGTH) { ccbh->status = CAM_CCB_LEN_ERR; break; } if (rdata_len > sizeof(rdata->inquiry_data)) rdata_len = sizeof(rdata->inquiry_data); rdata->inquiry_data.device = T_DIRECT; rdata->inquiry_data.version = SCSI_REV_SPC2; rdata->inquiry_data.response_format = 2; rdata->inquiry_data.additional_length = 32; bcopy("SATA ", rdata->inquiry_data.vendor, 8); bcopy(at->at_identify.model, rdata->inquiry_data.product, sizeof(rdata->inquiry_data.product)); bcopy(at->at_identify.firmware, rdata->inquiry_data.revision, sizeof(rdata->inquiry_data.revision)); ccbh->status = CAM_REQ_CMP; } /* * Use the vendor specific area to set the TRIM status * for scsi_da */ if (at->at_identify.support_dsm) { rdata->inquiry_data.vendor_specific1[0] = at->at_identify.support_dsm &ATA_SUPPORT_DSM_TRIM; rdata->inquiry_data.vendor_specific1[1] = at->at_identify.max_dsm_blocks; } break; case READ_CAPACITY_16: if (cdb->read_capacity_16.service_action != SRC16_SERVICE_ACTION) { ccbh->status = CAM_REQ_INVALID; break; } if (rdata_len < sizeof(rdata->read_capacity_data_16)) { ccbh->status = CAM_CCB_LEN_ERR; break; } /* fall through */ case READ_CAPACITY: if (rdata_len < sizeof(rdata->read_capacity_data)) { ccbh->status = CAM_CCB_LEN_ERR; break; } capacity = at->at_capacity; bzero(rdata, rdata_len); if (cdb->generic.opcode == READ_CAPACITY) { rdata_len = sizeof(rdata->read_capacity_data); if (capacity > 0xFFFFFFFFU) capacity = 0xFFFFFFFFU; bzero(&rdata->read_capacity_data, rdata_len); scsi_ulto4b((u_int32_t)capacity - 1, rdata->read_capacity_data.addr); scsi_ulto4b(512, rdata->read_capacity_data.length); } else { rdata_len = sizeof(rdata->read_capacity_data_16); bzero(&rdata->read_capacity_data_16, rdata_len); scsi_u64to8b(capacity - 1, rdata->read_capacity_data_16.addr); scsi_ulto4b(512, rdata->read_capacity_data_16.length); } ccbh->status = CAM_REQ_CMP; break; case SYNCHRONIZE_CACHE: /* * Synchronize cache. Specification says this can take * greater then 30 seconds so give it at least 45. */ fis = xa->fis; fis->flags = ATA_H2D_FLAGS_CMD; fis->command = ATA_C_FLUSH_CACHE; fis->device = 0; if (xa->timeout < 45000) xa->timeout = 45000; xa->datalen = 0; xa->flags = 0; xa->complete = ahci_ata_complete_disk_synchronize_cache; break; case TRIM: fis = xa->fis; fis->command = ATA_C_DATA_SET_MANAGEMENT; fis->features = (u_int8_t)ATA_SF_DSM_TRIM; fis->features_exp = (u_int8_t)(ATA_SF_DSM_TRIM>> 8); xa->flags = ATA_F_WRITE; fis->flags = ATA_H2D_FLAGS_CMD; xa->data = csio->data_ptr; xa->datalen = csio->dxfer_len; xa->timeout = ccbh->timeout*50; /* milliseconds */ fis->sector_count =(u_int8_t)(xa->datalen/512); fis->sector_count_exp =(u_int8_t)((xa->datalen/512)>>8); lba = 0; fis->lba_low = (u_int8_t)lba; fis->lba_mid = (u_int8_t)(lba >> 8); fis->lba_high = (u_int8_t)(lba >> 16); fis->lba_low_exp = (u_int8_t)(lba >> 24); fis->lba_mid_exp = (u_int8_t)(lba >> 32); fis->lba_high_exp = (u_int8_t)(lba >> 40); fis->device = ATA_H2D_DEVICE_LBA; xa->data = csio->data_ptr; xa->complete = ahci_ata_complete_disk_rw; ccbh->status = CAM_REQ_INPROG; break; case TEST_UNIT_READY: case START_STOP_UNIT: case PREVENT_ALLOW: /* * Just silently return success */ ccbh->status = CAM_REQ_CMP; rdata_len = 0; break; case ATA_PASS_12: atp12 = &cdb->ata_pass_12; fis = xa->fis; /* * Figure out the flags to be used, depending on the direction of the * CAM request. */ switch (ccbh->flags & CAM_DIR_MASK) { case CAM_DIR_IN: xa->flags = ATA_F_READ; break; case CAM_DIR_OUT: xa->flags = ATA_F_WRITE; break; default: xa->flags = 0; } xa->flags |= ATA_F_POLL | ATA_F_EXCLUSIVE; xa->data = csio->data_ptr; xa->datalen = csio->dxfer_len; xa->complete = ahci_ata_complete_disk_rw; xa->timeout = ccbh->timeout; /* * Populate the fis from the information we received through CAM * ATA passthrough. */ fis->flags = ATA_H2D_FLAGS_CMD; /* maybe also atp12->flags ? */ fis->features = atp12->features; fis->sector_count = atp12->sector_count; fis->lba_low = atp12->lba_low; fis->lba_mid = atp12->lba_mid; fis->lba_high = atp12->lba_high; fis->device = atp12->device; /* maybe always 0? */ fis->command = atp12->command; fis->control = atp12->control; /* * Mark as in progress so it is sent to the device. */ ccbh->status = CAM_REQ_INPROG; break; case ATA_PASS_16: atp16 = &cdb->ata_pass_16; fis = xa->fis; /* * Figure out the flags to be used, depending on the direction of the * CAM request. */ switch (ccbh->flags & CAM_DIR_MASK) { case CAM_DIR_IN: xa->flags = ATA_F_READ; break; case CAM_DIR_OUT: xa->flags = ATA_F_WRITE; break; default: xa->flags = 0; } xa->flags |= ATA_F_POLL | ATA_F_EXCLUSIVE; xa->data = csio->data_ptr; xa->datalen = csio->dxfer_len; xa->complete = ahci_ata_complete_disk_rw; xa->timeout = ccbh->timeout; /* * Populate the fis from the information we received through CAM * ATA passthrough. */ fis->flags = ATA_H2D_FLAGS_CMD; /* maybe also atp16->flags ? */ fis->features = atp16->features; fis->features_exp = atp16->features_ext; fis->sector_count = atp16->sector_count; fis->sector_count_exp = atp16->sector_count_ext; fis->lba_low = atp16->lba_low; fis->lba_low_exp = atp16->lba_low_ext; fis->lba_mid = atp16->lba_mid; fis->lba_mid_exp = atp16->lba_mid_ext; fis->lba_high = atp16->lba_high; fis->lba_mid_exp = atp16->lba_mid_ext; fis->device = atp16->device; /* maybe always 0? */ fis->command = atp16->command; /* * Mark as in progress so it is sent to the device. */ ccbh->status = CAM_REQ_INPROG; break; default: switch(cdb->generic.opcode) { case READ_6: lba = scsi_3btoul(cdb->rw_6.addr) & 0x1FFFFF; count = cdb->rw_6.length ? cdb->rw_6.length : 0x100; xa->flags = ATA_F_READ; break; case READ_10: lba = scsi_4btoul(cdb->rw_10.addr); count = scsi_2btoul(cdb->rw_10.length); xa->flags = ATA_F_READ; break; case READ_12: lba = scsi_4btoul(cdb->rw_12.addr); count = scsi_4btoul(cdb->rw_12.length); xa->flags = ATA_F_READ; break; case READ_16: lba = scsi_8btou64(cdb->rw_16.addr); count = scsi_4btoul(cdb->rw_16.length); xa->flags = ATA_F_READ; break; case WRITE_6: lba = scsi_3btoul(cdb->rw_6.addr) & 0x1FFFFF; count = cdb->rw_6.length ? cdb->rw_6.length : 0x100; xa->flags = ATA_F_WRITE; break; case WRITE_10: lba = scsi_4btoul(cdb->rw_10.addr); count = scsi_2btoul(cdb->rw_10.length); xa->flags = ATA_F_WRITE; break; case WRITE_12: lba = scsi_4btoul(cdb->rw_12.addr); count = scsi_4btoul(cdb->rw_12.length); xa->flags = ATA_F_WRITE; break; case WRITE_16: lba = scsi_8btou64(cdb->rw_16.addr); count = scsi_4btoul(cdb->rw_16.length); xa->flags = ATA_F_WRITE; break; default: ccbh->status = CAM_REQ_INVALID; break; } if (ccbh->status != CAM_REQ_INPROG) break; fis = xa->fis; fis->flags = ATA_H2D_FLAGS_CMD; fis->lba_low = (u_int8_t)lba; fis->lba_mid = (u_int8_t)(lba >> 8); fis->lba_high = (u_int8_t)(lba >> 16); fis->device = ATA_H2D_DEVICE_LBA; /* * NCQ only for direct-attached disks, do not currently * try to use NCQ with port multipliers. */ if (at->at_ncqdepth > 1 && ap->ap_type == ATA_PORT_T_DISK && (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) && (ccbh->flags & CAM_POLLED) == 0) { /* * Use NCQ - always uses 48 bit addressing */ xa->flags |= ATA_F_NCQ; fis->command = (xa->flags & ATA_F_WRITE) ? ATA_C_WRITE_FPDMA : ATA_C_READ_FPDMA; fis->lba_low_exp = (u_int8_t)(lba >> 24); fis->lba_mid_exp = (u_int8_t)(lba >> 32); fis->lba_high_exp = (u_int8_t)(lba >> 40); fis->sector_count = xa->tag << 3; fis->features = (u_int8_t)count; fis->features_exp = (u_int8_t)(count >> 8); } else if (count > 0x100 || lba > 0x0FFFFFFFU) {