static void ad_init(device_t dev) { struct ata_device *atadev = device_get_softc(dev); ATA_SETMODE(device_get_parent(dev), dev); /* enable readahead caching */ if (atadev->param.support.command1 & ATA_SUPPORT_LOOKAHEAD) ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); /* enable write caching if supported and configured */ if (atadev->param.support.command1 & ATA_SUPPORT_WRITECACHE) { if (ata_wc) ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); else ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); } /* use multiple sectors/interrupt if device supports it */ if (ad_version(atadev->param.version_major)) { int secsperint = max(1, min(atadev->param.sectors_intr & 0xff, 16)); if (!ata_controlcmd(dev, ATA_SET_MULTI, 0, 0, secsperint)) atadev->max_iosize = secsperint * DEV_BSIZE; } else atadev->max_iosize = DEV_BSIZE; }
static int afd_reinit(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); struct afd_softc *fdp = device_get_ivars(dev); if (((atadev->unit == ATA_MASTER) && !(ch->devices & ATA_ATAPI_MASTER)) || ((atadev->unit == ATA_SLAVE) && !(ch->devices & ATA_ATAPI_SLAVE))) { device_set_ivars(dev, NULL); kfree(fdp, M_AFD); return 1; } ATA_SETMODE(device_get_parent(dev), dev); return 0; }
static int afd_attach(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); struct afd_softc *fdp; cdev_t cdev; fdp = kmalloc(sizeof(struct afd_softc), M_AFD, M_WAITOK | M_ZERO); device_set_ivars(dev, fdp); ATA_SETMODE(device_get_parent(dev), dev); if (afd_sense(dev)) { device_set_ivars(dev, NULL); kfree(fdp, M_AFD); return ENXIO; } atadev->flags |= ATA_D_MEDIA_CHANGED; /* create the disk device */ devstat_add_entry(&fdp->stats, "afd", device_get_unit(dev), DEV_BSIZE, DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_WFD); cdev = disk_create(device_get_unit(dev), &fdp->disk, &afd_ops); disk_setdisktype(&fdp->disk, "floppy"); cdev->si_drv1 = dev; if (ch->dma) cdev->si_iosize_max = ch->dma->max_iosize; else cdev->si_iosize_max = min(MAXPHYS,64*1024); fdp->cdev = cdev; /* announce we are here */ afd_describe(dev); return 0; }
static void ataaction(struct cam_sim *sim, union ccb *ccb) { device_t dev, parent; struct ata_channel *ch; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ataaction func_code=%x\n", ccb->ccb_h.func_code)); ch = (struct ata_channel *)cam_sim_softc(sim); dev = ch->dev; switch (ccb->ccb_h.func_code) { /* Common cases first */ case XPT_ATA_IO: /* Execute the requested I/O operation */ case XPT_SCSI_IO: if (ata_check_ids(dev, ccb)) return; if ((ch->devices & ((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << ccb->ccb_h.target_id)) == 0) { ccb->ccb_h.status = CAM_SEL_TIMEOUT; break; } if (ch->running) device_printf(dev, "already running!\n"); if (ccb->ccb_h.func_code == XPT_ATA_IO && (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && (ccb->ataio.cmd.control & ATA_A_RESET)) { struct ata_res *res = &ccb->ataio.res; bzero(res, sizeof(*res)); if (ch->devices & (ATA_ATA_MASTER << ccb->ccb_h.target_id)) { res->lba_high = 0; res->lba_mid = 0; } else { res->lba_high = 0xeb; res->lba_mid = 0x14; } ccb->ccb_h.status = CAM_REQ_CMP; break; } ata_cam_begin_transaction(dev, ccb); return; case XPT_EN_LUN: /* Enable LUN as a target */ case XPT_TARGET_IO: /* Execute target I/O request */ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ case XPT_ABORT: /* Abort the specified CCB */ /* XXX Implement */ ccb->ccb_h.status = CAM_REQ_INVALID; break; case XPT_SET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; struct ata_cam_device *d; if (ata_check_ids(dev, ccb)) return; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) d = &ch->curr[ccb->ccb_h.target_id]; else d = &ch->user[ccb->ccb_h.target_id]; if (ch->flags & ATA_SATA) { if (cts->xport_specific.sata.valid & CTS_SATA_VALID_REVISION) d->revision = cts->xport_specific.sata.revision; if (cts->xport_specific.sata.valid & CTS_SATA_VALID_MODE) { if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { d->mode = ATA_SETMODE(ch->dev, ccb->ccb_h.target_id, cts->xport_specific.sata.mode); } else d->mode = cts->xport_specific.sata.mode; } if (cts->xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) d->bytecount = min(8192, cts->xport_specific.sata.bytecount); if (cts->xport_specific.sata.valid & CTS_SATA_VALID_ATAPI) d->atapi = cts->xport_specific.sata.atapi; if (cts->xport_specific.sata.valid & CTS_SATA_VALID_CAPS) d->caps = cts->xport_specific.sata.caps; } else { if (cts->xport_specific.ata.valid & CTS_ATA_VALID_MODE) { if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { d->mode = ATA_SETMODE(ch->dev, ccb->ccb_h.target_id, cts->xport_specific.ata.mode); } else d->mode = cts->xport_specific.ata.mode; } if (cts->xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) d->bytecount = cts->xport_specific.ata.bytecount; if (cts->xport_specific.ata.valid & CTS_ATA_VALID_ATAPI) d->atapi = cts->xport_specific.ata.atapi; if (cts->xport_specific.ata.valid & CTS_ATA_VALID_CAPS) d->caps = cts->xport_specific.ata.caps; } ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; struct ata_cam_device *d; if (ata_check_ids(dev, ccb)) return; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) d = &ch->curr[ccb->ccb_h.target_id]; else d = &ch->user[ccb->ccb_h.target_id]; cts->protocol = PROTO_UNSPECIFIED; cts->protocol_version = PROTO_VERSION_UNSPECIFIED; if (ch->flags & ATA_SATA) { cts->transport = XPORT_SATA; cts->transport_version = XPORT_VERSION_UNSPECIFIED; cts->xport_specific.sata.valid = 0; cts->xport_specific.sata.mode = d->mode; cts->xport_specific.sata.valid |= CTS_SATA_VALID_MODE; cts->xport_specific.sata.bytecount = d->bytecount; cts->xport_specific.sata.valid |= CTS_SATA_VALID_BYTECOUNT; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { cts->xport_specific.sata.revision = ATA_GETREV(dev, ccb->ccb_h.target_id); if (cts->xport_specific.sata.revision != 0xff) { cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION; } cts->xport_specific.sata.caps = d->caps & CTS_SATA_CAPS_D; if (ch->pm_level) { cts->xport_specific.sata.caps |= CTS_SATA_CAPS_H_PMREQ; } cts->xport_specific.sata.caps &= ch->user[ccb->ccb_h.target_id].caps; } else { cts->xport_specific.sata.revision = d->revision; cts->xport_specific.sata.valid |= CTS_SATA_VALID_REVISION; cts->xport_specific.sata.caps = d->caps; } cts->xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; cts->xport_specific.sata.atapi = d->atapi; cts->xport_specific.sata.valid |= CTS_SATA_VALID_ATAPI; } else { cts->transport = XPORT_ATA; cts->transport_version = XPORT_VERSION_UNSPECIFIED; cts->xport_specific.ata.valid = 0; cts->xport_specific.ata.mode = d->mode; cts->xport_specific.ata.valid |= CTS_ATA_VALID_MODE; cts->xport_specific.ata.bytecount = d->bytecount; cts->xport_specific.ata.valid |= CTS_ATA_VALID_BYTECOUNT; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { cts->xport_specific.ata.caps = d->caps & CTS_ATA_CAPS_D; if (!(ch->flags & ATA_NO_48BIT_DMA)) cts->xport_specific.ata.caps |= CTS_ATA_CAPS_H_DMA48; cts->xport_specific.ata.caps &= ch->user[ccb->ccb_h.target_id].caps; } else cts->xport_specific.ata.caps = d->caps; cts->xport_specific.ata.valid |= CTS_ATA_VALID_CAPS; cts->xport_specific.ata.atapi = d->atapi; cts->xport_specific.ata.valid |= CTS_ATA_VALID_ATAPI; } ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_RESET_BUS: /* Reset the specified SCSI bus */ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ ata_reinit(dev); ccb->ccb_h.status = CAM_REQ_CMP; break; case XPT_TERM_IO: /* Terminate the I/O process */ /* XXX Implement */ ccb->ccb_h.status = CAM_REQ_INVALID; break; case XPT_PATH_INQ: /* Path routing inquiry */ { struct ccb_pathinq *cpi = &ccb->cpi; parent = device_get_parent(dev); cpi->version_num = 1; /* XXX??? */ cpi->hba_inquiry = PI_SDTR_ABLE; cpi->target_sprt = 0; cpi->hba_misc = PIM_SEQSCAN; cpi->hba_eng_cnt = 0; if (ch->flags & ATA_NO_SLAVE) cpi->max_target = 0; else cpi->max_target = 1; cpi->max_lun = 0; cpi->initiator_id = 0; cpi->bus_id = cam_sim_bus(sim); if (ch->flags & ATA_SATA) cpi->base_transfer_speed = 150000; else cpi->base_transfer_speed = 3300; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "ATA", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); if (ch->flags & ATA_SATA) cpi->transport = XPORT_SATA; else cpi->transport = XPORT_ATA; cpi->transport_version = XPORT_VERSION_UNSPECIFIED; cpi->protocol = PROTO_ATA; cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; cpi->maxio = ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS; if (device_get_devclass(device_get_parent(parent)) == devclass_find("pci")) { cpi->hba_vendor = pci_get_vendor(parent); cpi->hba_device = pci_get_device(parent); cpi->hba_subvendor = pci_get_subvendor(parent); cpi->hba_subdevice = pci_get_subdevice(parent); } cpi->ccb_h.status = CAM_REQ_CMP; break; } default: ccb->ccb_h.status = CAM_REQ_INVALID; break; } xpt_done(ccb); }
int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data) { struct ata_device *atadev = device_get_softc(dev); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_ioc_request *ioc_request = (struct ata_ioc_request *)data; struct ata_params *params = (struct ata_params *)data; int *mode = (int *)data; struct ata_request *request; caddr_t buf; int error; switch (cmd) { case IOCATAREQUEST: if (ioc_request->count > (ch->dma->max_iosize ? ch->dma->max_iosize : DFLTPHYS)) { return (EFBIG); } if (!(buf = malloc(ioc_request->count, M_ATA, M_NOWAIT))) { return ENOMEM; } if (!(request = ata_alloc_request())) { free(buf, M_ATA); return ENOMEM; } if (ioc_request->flags & ATA_CMD_WRITE) { error = copyin(ioc_request->data, buf, ioc_request->count); if (error) { free(buf, M_ATA); ata_free_request(request); return error; } } request->dev = dev; if (ioc_request->flags & ATA_CMD_ATAPI) { request->flags = ATA_R_ATAPI; bcopy(ioc_request->u.atapi.ccb, request->u.atapi.ccb, 16); } else { request->u.ata.command = ioc_request->u.ata.command; request->u.ata.feature = ioc_request->u.ata.feature; request->u.ata.lba = ioc_request->u.ata.lba; request->u.ata.count = ioc_request->u.ata.count; } request->timeout = ioc_request->timeout; request->data = buf; request->bytecount = ioc_request->count; request->transfersize = request->bytecount; if (ioc_request->flags & ATA_CMD_CONTROL) request->flags |= ATA_R_CONTROL; if (ioc_request->flags & ATA_CMD_READ) request->flags |= ATA_R_READ; if (ioc_request->flags & ATA_CMD_WRITE) request->flags |= ATA_R_WRITE; ata_queue_request(request); if (request->flags & ATA_R_ATAPI) { bcopy(&request->u.atapi.sense, &ioc_request->u.atapi.sense, sizeof(struct atapi_sense)); } else { ioc_request->u.ata.command = request->u.ata.command; ioc_request->u.ata.feature = request->u.ata.feature; ioc_request->u.ata.lba = request->u.ata.lba; ioc_request->u.ata.count = request->u.ata.count; } ioc_request->error = request->result; if (ioc_request->flags & ATA_CMD_READ) error = copyout(buf, ioc_request->data, ioc_request->count); else error = 0; free(buf, M_ATA); ata_free_request(request); return error; case IOCATAGPARM: ata_getparam(atadev, 0); bcopy(&atadev->param, params, sizeof(struct ata_params)); return 0; case IOCATASMODE: atadev->mode = *mode; ATA_SETMODE(device_get_parent(dev), dev); return 0; case IOCATAGMODE: *mode = atadev->mode; return 0; case IOCATASSPINDOWN: atadev->spindown = *mode; return 0; case IOCATAGSPINDOWN: *mode = atadev->spindown; return 0; default: return ENOTTY; } }