📄 scsi_disk.c
字号:
*/ if (!suser()) return(EACCES); /* * CDROM is read only, don't allow set partition table. */ if (sc->sc_devtyp[targid] & SZ_CDROM) return(EROFS); /* * Before we set the new partition tables make sure * that it will no corrupt any of the kernel data * structures. */ if ((error = ptcmp(dev, &sz_part[unit], pt)) != 0) return(error); /* * Using the user's data to set the partition table * for the pack */ sz_part[unit] = *pt; /* * See if we need to update the superblock of the * "a" partition of this disk. */ ssblk(dev, pt); /* * Just make sure that we set the valid bit. */ sz_part[unit].pt_valid = PT_VALID; break; case DEVIOCGET: /* device status */ devget = (struct devget *)data; bzero(devget,sizeof(struct devget)); devget->category = DEV_DISK; devget->bus = DEV_NB; bcopy(DEV_VS_SCSI, devget->interface, strlen(DEV_VS_SCSI)); bcopy(sc->sc_device[targid], devget->device, DEV_SIZE); devget->adpt_num = 0; devget->nexus_num = 0; devget->bus_num = 0; devget->ctlr_num = cntlr; devget->rctlr_num = 0; devget->slave_num = targid; bcopy("rz", devget->dev_name, 3); devget->unit_num = unit; devget->soft_count = sc->sc_softcnt[targid]; devget->hard_count = sc->sc_hardcnt[targid]; devget->stat = sc->sc_flags[targid]; if (sc->sc_devtyp[targid] & SZ_CDROM) { /* To make sure we don't break the installation! */ devget->stat |= DEV_WRTLCK; } else { /* * 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 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; /* TODO: 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;{ register struct uba_ctlr *um; register struct buf *dp; register int s; int unit; int targid; int cntlr; register struct sz_softc *sc; struct uba_device *ui; int release; unit = minor(bp->b_dev) >> 3; ui = szdinfo[unit]; dp = &szutab[unit]; targid = ui->ui_slave; cntlr = ui->ui_ctlr; sc = &sz_softc[cntlr]; 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, 0x4, ("resid = %d\n", bp->b_resid)); sc->sc_flags[targid] |= DEV_DONE; PRINTD(targid, 0x4, ("biodone on bp %x\n", bp)); biodone(bp); 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) );}/* * * Name: rzspecial -Disk Special commands routine * * Abstract: This routine is called from rzioctl() to execute * "special" commands, such as: format unit, read * defect data, veify data, and reassign block. * Also: inquiry, mode sense, mode select. * * Inputs: * * dev ULTRIX major/minor device number. * cmd Command to execute. * data Pointer to data for command. * * Outputs: * Some commands pass data back to caller. * * Return Values: * * ENXIO Non supported command. * EBUSY Special command already in progress. * ENOMEM Cannot get memory for command data. * EACCES Must be superuser for this command. * EFAULT copyin() of command data failed. * EIO Command, such as reassign block, failed. * * Side Effects: * Most of the SCSI driver is used to execute * these "special" commands. * KM_ALLOC/KM_FREE called. * */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 = minor(dev) >> 3; int cntlr; int reterr; int targid; 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); case SCSI_VERIFY_DATA: case SCSI_MODE_SELECT: case SCSI_MODE_SENSE: case SCSI_GET_SENSE: case SCSI_GET_INQUIRY_DATA: break; default: return(ENXIO); } } 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); } 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); } else { KM_ALLOC(sc->sc_rzaddr[targid], char *, sizeof(*dd), KM_DEVBUF, KM_CLEAR); } 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -