📄 scsi_disk.c
字号:
/* * Do a mode sense (page one) to see if the * device is write locked. First one can fail * due to unit attention. * NOTE: RX23 fails if we don't ask for a page. */ rzcommand(dev, SZ_MODSNS, 1, 0); if (sc->sc_c_status[targid] != SZ_GOOD) rzcommand(dev, SZ_MODSNS, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) { msdp = (struct sz_rzmodsns_dt *)&sc->sz_dat[targid]; if (msdp->wp) devget->stat |= DEV_WRTLCK; } } devget->category_stat = DEV_DISKPART; if ((sdp->flags & SCSI_REMOVABLE_DISK) == 0) break; /* first one can fail due to unit attention */ rzcommand(dev, SZ_RDCAP, 1, 0); rzcommand(dev, SZ_RDCAP, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) { rdp = (struct sz_rdcap_dt *)&sc->sz_dat[targid]; i = (rdp->lbaddr3 << 24) & 0xff000000; i |= (rdp->lbaddr2 << 16) & 0x00ff0000; i |= (rdp->lbaddr1 << 8) & 0x0000ff00; i |= rdp->lbaddr0 & 0x000000ff; /* * RDCAP returns the address of the last LBN. * We must add one to get the number of LBNs. */ i++; switch(i) { case 5760: devget->category_stat |= DEV_3_ED2S; break; case 2880: devget->category_stat |= DEV_3_HD2S; break; case 1440: if (sc->sc_devtyp[targid] == RX33) { devget->category_stat |= DEV_5_DD2S; } else { devget->category_stat |= DEV_3_DD2S; } break; case 2400: devget->category_stat |= DEV_5_HD2S; break; case 800: devget->category_stat |= DEV_5_DD1S; break; case 720: devget->category_stat |= DEV_5_LD2S; break; default: devget->category_stat |= DEV_X_XXXX; break; } } else devget->category_stat |= DEV_X_XXXX; devget->category_stat |= DEV_MC_COUNT; devget->category_stat |= (sc->sc_mc_cnt[targid] << 16); break; case DEVGETGEOM: /* disk geometry info */ devgeom = (DEVGEOMST *)data; bzero(devgeom, sizeof(DEVGEOMST)); if (sc->sc_rmv_media & (1 << targid)) devgeom->geom_info.attributes |= DEVGEOM_REMOVE; /* * Get disk size via read capacity command. * First one can fail due to unit attention. */ rzcommand(dev, SZ_RDCAP, 1, 0); if (sc->sc_c_status[targid] != SZ_GOOD) rzcommand(dev, SZ_RDCAP, 1, 0); if (sc->sc_c_status[targid] == SZ_GOOD) { rdp = (struct sz_rdcap_dt *)&sc->sz_dat[targid]; i = sz_sbtol(&rdp->lbaddr3); /* * RDCAP returns the address of the last LBN. * We must add one to get the number of LBNs. */ i++; devgeom->geom_info.dev_size = i; } else return(EIO); /* * Get disk geometry from some combination of mode sense * pages 3, 4, and 5. Normally 3 and 4 for hard disks, * 5 for floppy disks. We get the current values. * NOTE: we check the page code because a brain damaged * hard disk returned a bogus page instead of a * check condition for an unsupported page (page 5). */ rzcommand(dev, SZ_MODSNS, 3, 0); /* page 3 */ if (sc->sc_c_status[targid] == SZ_GOOD) { msdp = (struct sz_rzmodsns_dt *)&sc->sz_dat[targid]; p3 = (struct page_code_3 *)msdp->mspage; if (p3->pgcode == 3) { i = (p3->spt1 << 8) & 0x0000ff00; i |= p3->spt0 & 0x000000ff; devgeom->geom_info.nsectors = i; } } rzcommand(dev, SZ_MODSNS, 4, 0); /* page 4 */ if (sc->sc_c_status[targid] == SZ_GOOD) { msdp = (struct sz_rzmodsns_dt *)&sc->sz_dat[targid]; p4 = (struct page_code_4 *)msdp->mspage; if (p4->pgcode == 4) { i = (p4->ncyl2 << 16) & 0x00ff0000; i |= (p4->ncyl1 << 8) & 0x0000ff00; i |= p4->ncyl0 & 0x000000ff; devgeom->geom_info.ncylinders = i; devgeom->geom_info.ntracks = p4->nheads; } } rzcommand(dev, SZ_MODSNS, 5, 0); /* page 5 */ if (sc->sc_c_status[targid] == SZ_GOOD) { msdp = (struct sz_rzmodsns_dt *)&sc->sz_dat[targid]; p5 = (struct page_code_5 *)msdp->mspage; if (p5->pgcode == 5) { i = (p5->num_cyl1 << 8) & 0x0000ff00; i |= (p5->num_cyl0 & 0x000000ff); devgeom->geom_info.ncylinders = i; devgeom->geom_info.ntracks = p5->num_heads; devgeom->geom_info.nsectors = p5->sec_per_trk; } } /* fail if no geometry info available (RRD40 does this) */ if ((devgeom->geom_info.ntracks == 0) || (devgeom->geom_info.nsectors == 0) || (devgeom->geom_info.ncylinders == 0)) return(EIO); break; case CDROM_PAUSE_PLAY: case CDROM_RESUME_PLAY: case CDROM_PLAY_AUDIO: case CDROM_PLAY_AUDIO_MSF: case CDROM_PLAY_AUDIO_TI: case CDROM_PLAY_AUDIO_TR: case CDROM_TOC_HEADER: case CDROM_TOC_ENTRYS: case CDROM_EJECT_CADDY: case CDROM_READ_SUBCHANNEL: case CDROM_READ_HEADER: case CDROM_PLAY_VAUDIO: case CDROM_PLAY_MSF: case CDROM_PLAY_TRACK: case CDROM_PLAYBACK_CONTROL: case CDROM_PLAYBACK_STATUS: case CDROM_SET_ADDRESS_FORMAT: if ((sc->sc_devtyp[targid] & SZ_CDROM) == 0) { return (EINVAL); } /* FALLTHROUGH */ case SCSI_STOP_UNIT: case SCSI_START_UNIT: case SCSI_ALLOW_REMOVAL: case SCSI_PREVENT_REMOVAL: case SCSI_READ_CAPACITY: case SCSI_SEEK_POSITION: case SCSI_SEND_DIAGNOSTIC: case SCSI_RECEIVE_DIAGNOSTIC: case SCSI_FORMAT_UNIT: case SCSI_REASSIGN_BLOCK: case SCSI_READ_DEFECT_DATA: case SCSI_VERIFY_DATA: case SCSI_MODE_SENSE: case SCSI_MODE_SELECT: case SCSI_GET_SENSE: case SCSI_GET_INQUIRY_DATA: case SCSI_READ_LONG: case SCSI_WRITE_LONG: return(rzspecial(dev, cmd, data)); break; /* TODO1: do I need DKIOCACC (bbr from sdc.c) radisk uses it */ default: return (ENXIO); } return (0);}/* * * Name: rzcomplete -Disk completion routine * * Abstract: This routine is called from the scsi state machine * to perform the completion work for the current data * transfer. * * Inputs: * * bp Buffer pointer of command to be completed. * * Outputs: Only printing debug messages. * * Return Values: Nothing formal, b_resid is updated. * * Side Effects: * biodone() is called to free up the current bp. * The buffer queue is changed to free up the front entry. * The DBBR code will be called if a read error occured. * */int rzcomplete( bp ) struct buf *bp;{ struct sz_softc *sc; struct uba_device *ui; register struct buf *dp; int unit; int targid; int release; unit = minor(bp->b_dev) >> 3; ui = szdinfo[unit]; sc = &sz_softc[ui->ui_ctlr]; targid = ui->ui_slave; dp = &szutab[unit]; release = 1; /* release the buffer from the queue */ PRINTD( targid, 0x01, ("rzcomplete called unit %d\n", unit) ); /* Check for existing BBR state or a if bad block was encountered. */ if((sc->sc_szflags[targid] & SZ_RECOVERED) || (sc->sc_bbr_active[ targid ])) { /* Call the BBR routine to handle the BBR tasks. */ release = rz_bbr( sc, targid, bp ); } /* Remove the completed request from the queue and release the buffer. */ /* TODO: are we absolutely sure dp is valid? */ if( release ) { /* Update the pointer value for bp. It is possible that the BBR code had inserted and removed a buffer on the queue. If the "current" one did belong to the BBR code, it has been removed and the value for bp from the parameter call is incorrect. To be sure to grab the correct buffer from the front of the queue, get it via dp. */ bp = dp->b_actf; /* go via dp, just in case */ dp->b_actf = bp->av_forw; bp->b_resid = sc->sc_resid[targid]; PRINTD(targid, 0x5, ("rzcomplete: resid = %d\n", bp->b_resid)); PRINTD(targid, 0x4, ("biodone on bp %x\n", bp)); biodone(bp); sc->sc_flags[targid] |= DEV_DONE; sc->sc_xevent[targid] = SZ_BEGIN; sz_retries[sc->sc_unit[targid]] = 0; /* The comand has ended */ dp->b_active = 0; } PRINTD( targid, 0x01, ("rzcomplete exiting %d\n", unit) );}rzspecial(dev, cmd, data) dev_t dev; register int cmd; caddr_t data;{ struct format_params *fp; struct reassign_params *rp; struct read_defect_params *rdp; struct verify_params *vp; struct mode_sel_sns_params *msp; struct extended_sense *es; struct defect_descriptors *dd; struct inquiry_info *inq; struct io_uxfer *iox; struct buf *bp; register struct uba_device *ui; register struct sz_softc *sc; int unit; int cntlr; int reterr; int targid; int rzaddr_length; unit = minor(dev) >> 3; ui = szdinfo[unit]; cntlr = ui->ui_ctlr; targid = ui->ui_slave; sc = &sz_softc[cntlr]; bp = &cszbuf[unit]; reterr = 0; /* * CDROM is read only. Cannot allow all commands. */ if (sc->sc_devtyp[targid] & SZ_CDROM) { switch (cmd) { case SCSI_FORMAT_UNIT: case SCSI_REASSIGN_BLOCK: case SCSI_READ_DEFECT_DATA: return (EROFS); default: break; } /* * Ensure no other I/O is active for this CD-ROM. This * allows multiple processes to issue audio commands. */ if (reterr = rziowait (bp, sc->sc_rzspecial[targid])) { return (reterr); } } else { if (sc->sc_rzspecial[targid]) { return (EBUSY); } /* * Ensure buffer is available before setting the special * flag below, since this flag controls error logging. */ if (reterr = rziowait (bp, sc->sc_rzspecial[targid])) { return (reterr); } } /* * Allocate kernel memory for the scsi command ioctl * parameters and data, and for the defect lists. * Allocate the header once and don't free it. */ if (sc->sc_rzparams[targid] == NULL) { KM_ALLOC(sc->sc_rzparams[targid], char *, sizeof(union rzdisk_params), KM_DEVBUF, KM_CLEAR); if(sc->sc_rzparams[targid] == NULL) return(ENOMEM); } PRINTD (targid, 0x20, ("Allocated rzparam buffer at 0x%x of %d bytes.\n", sc->sc_rzparams[targid], sizeof(union rzdisk_params))); if ((cmd == SCSI_MODE_SELECT) || (cmd == SCSI_MODE_SENSE) || (cmd == SCSI_GET_INQUIRY_DATA)) { bcopy(data, sc->sc_rzparams[targid], sizeof(*msp)); msp = (struct mode_sel_sns_params *)sc->sc_rzparams[targid]; KM_ALLOC(sc->sc_rzaddr[targid], char *, msp->msp_length, KM_DEVBUF, (KM_CLEAR | KM_NOWAIT)); rzaddr_length = msp->msp_length; } else { KM_ALLOC(sc->sc_rzaddr[targid], char *, sizeof(*dd), KM_DEVBUF, (KM_CLEAR | KM_NOWAIT)); rzaddr_length = sizeof(*dd); } PRINTD (targid, 0x20, ("Allocated rzaddr buffer at 0x%x of %d bytes.\n", sc->sc_rzaddr[targid], rzaddr_length)); if(sc->sc_rzaddr[targid] == NULL) return(ENOMEM); sc->sc_rzspecial[targid] = 1; /* Show special command active. */ switch(cmd) { case SCSI_FORMAT_UNIT: /* * Must be super user to FORMAT a disk. */ if (!suser()) { reterr = EACCES; break; } fp = (struct format_params *)data; bcopy(data, sc->sc_rzparams[targid], sizeof(*fp)); /* * Copy in the defect list from user space. * We don't supply a defect list with the format command. * The length field is always zero. */ if(fp->fp_length != 0) { if(copyin(fp->fp_addr, sc->sc_rzaddr[targid], sizeof(*dd)) != 0) { reterr = EFAULT; break; } } if ((reterr = rzcommand (dev, SZ_FORMAT, 1, 0)) == EINTR) { break; } /* mark unit offline (format could change disk's size) */ sz_unit_online[unit] = 0; if (sc->sc_c_status[targid] != SZ_GOOD) { mprintf("rzspecial: %s unit %d: format unit failed\n", sc->sc_device[targid], unit); reterr = EIO; } break; case SCSI_REASSIGN_BLOCK: /* * Must be super user to REASSIGN a bad block. */ if (!suser()) { reterr = EACCES; break; } bcopy(data, sc->sc_rzparams[targid], sizeof(*rp)); if ((reterr = rzcommand (dev, SZ_REASSIGN, 1, 0)) == EINTR) { break; } if(sc->sc_c_status[targid] != SZ_GOOD) { mprintf("rzspecial: %s unit %d: reassign block failed\n", sc->sc_device[targid], unit); reterr = EIO; } break; case SCSI_READ_DEFECT_DATA: rdp = (struct read_defect_params *)data; bcopy(data, sc->sc_rzparams[targid], sizeof(*rdp));/* vslock(rdp->rdp_addr, sizeof(*dd)); */ if ((reterr = rzcommand (dev, SZ_RDD, 1, 0)) == EINTR) { break; }/* vsunlock(rdp->rdp_addr, sizeof(*dd), B_READ); */ if(sc->sc_c_status[targid] != SZ_GOOD) { mprintf("rzspecial: %s unit %d: read defect data failed\n", sc->sc_device[targid], unit); reterr = EIO; break; } /* * Copy out the defect list to user space. */ if(copyout(sc->sc_rzaddr[targid], rdp->rdp_addr, sizeof(*dd)) != 0) reterr = EFAULT; break; case SCSI_WRITE_LONG: iox = (struct io_uxfer *)data; if( iox->io_cnt > sizeof(*dd) ){ reterr = EINVAL; break; } bcopy(data, sc->sc_rzparams[targid], sizeof(*iox)); /* * Copy in the write long data from user space. */ if(copyin( iox->io_addr, sc->sc_rzaddr[targid],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -