📄 sd.c
字号:
}/* * System Crash Dump routine */#define NDUMP_RETRIES 5intsddump(dev, addr, blkno, nblk)dev_t dev;caddr_t addr;daddr_t blkno;int nblk;{ struct dk_map *lp; struct scsi_device *devp; struct scsi_disk *un; struct scsi_pkt *pkt; register s, i, pflag; int err; if (SDUNIT(dev) >= SD_MAXUNIT) { return (ENXIO); } else if (!(devp = sdunits[SDUNIT(dev)]) || !devp->sd_present || !(un = UPTR) || !un->un_gvalid) { return (ENXIO); } lp = &un->un_map[SDPART(dev)]; if (blkno+nblk > lp->dkl_nblk) { return (EINVAL); } /* * The first time through, reset the specific target device. * Do a REQUEST SENSE if required. */ pflag = FLAG_NOINTR|FLAG_NODISCON; if (un->un_dp->options & SD_NOPARITY) pflag |= FLAG_NOPARITY; un->un_rqs->pkt_flags |= pflag; s = splr(sdpri); if (un->un_state != SD_STATE_DUMPING) { New_state(un, SD_STATE_DUMPING); /* * Abort any active commands for this target */ (void) scsi_abort(ROUTE, (struct scsi_pkt *) 0); /* * Reset the bus. I'd like to not have to do this, * but this is the safest thing to do... */ if (scsi_reset(ROUTE, RESET_ALL) == 0) { (void) splx(s); return (EIO); } DELAY(2*1000000); for (i = 0; i < NDUMP_RETRIES; i++) { if (scsi_poll(un->un_rqs)) { (void) splx(s); return (EIO); } if (SCBP_C(un->un_rqs) == STATUS_GOOD) break; DELAY(10000); } } (void) splx(s); blkno += (lp->dkl_cylno * un->un_g.dkg_nhead * un->un_g.dkg_nsect); /* * It should be safe to call the allocator here without * worrying about being locked for DVMA mapping because * the address we're passed is already a DVMA mapping */ bzero((caddr_t) un->un_sbufp, sizeof (struct buf)); un->un_sbufp->b_un.b_addr = addr; un->un_sbufp->b_bcount = nblk << DEV_BSHIFT; pkt = scsi_resalloc(ROUTE, CDB_GROUP1, 1, (opaque_t) un->un_sbufp, NULL_FUNC); if (pkt == (struct scsi_pkt *) 0) { sdlog(devp, LOG_CRIT, "no resources for dumping"); return (EIO); } if (blkno >= (1<<20)) { makecom_g1(pkt, devp, pflag, SCMD_WRITE_G1, (int) blkno, nblk); } else { makecom_g0(pkt, devp, pflag, SCMD_WRITE, (int) blkno, nblk); } s = splr(sdpri); for (err = EIO, i = 0; i < NDUMP_RETRIES && err == EIO; i++) { if (scsi_poll(pkt)) { if (scsi_reset(ROUTE, RESET_ALL) == 0) { break; } } switch (SCBP_C(pkt)) { case STATUS_GOOD: err = 0; break; case STATUS_BUSY: DELAY(5*1000000); break; case STATUS_CHECK: /* * Hope this clears it up... */ (void) scsi_poll(un->un_rqs); break; default: break; } } (void) splx(s); scsi_resfree(pkt); return (err);}/* * This routine implements the ioctl calls. It is called * from the device switch at normal priority. *//*ARGSUSED3*/sdioctl(dev, cmd, data, flag)dev_t dev;int cmd;caddr_t data;int flag;{ extern char *strcpy(); register struct scsi_device *devp; register struct scsi_disk *un; struct dk_map *lp; struct dk_info *info; struct dk_conf *conf; struct dk_diag *diag; int unit, i, s, part; if ((unit = SDUNIT(dev)) >= SD_MAXUNIT || !(devp = sdunits[unit]) || !(devp->sd_present) || !(un = UPTR) || (un->un_state == SD_STATE_DETACHING)) { return (ENXIO); } part = SDPART(dev); lp = &un->un_map[part]; switch (cmd) { case DKIOCWCHK: { int pbit = (1<<part); if (!suser()) { return (u.u_error); } else if (lp->dkl_nblk == 0) { return (ENXIO); } if (un->un_dp->options & SD_NOVERIFY) { return (ENOTTY); } i = (*((int *) data)); if (i) { s = splr(sdpri); (*((int *) data)) = ((un->un_wchkmap & pbit) != 0); un->un_wchkmap |= pbit; /* VM HACK!!! */#ifdef VAC {#ifdef sun4#include <machine/cpu.h> extern int cpu, vac, nopagereclaim; /* VM HACK!!! */ if (cpu == CPU_SUN4_260 && vac) { nopagereclaim = 1; }#endif sun4#ifdef sun3#include <machine/cpu.h> extern int cpu, vac, nopagereclaim; if (cpu == CPU_SUN3_260 && vac) { nopagereclaim = 1; }#endif sun4 }#endif VAC (void) splx(s); printf("sd%d%c: write check enabled\n", unit, 'a' + part); } else { s = splr(sdpri); (*((int *) data)) = ((un->un_wchkmap & pbit) != 0); un->un_wchkmap &= ~pbit; (void) splx(s); printf("sd%d%c: write check disabled\n", unit, 'a' + part); } return (0); } case DKIOCINFO: /* * Return info concerning the controller. */ info = (struct dk_info *)data;#ifdef OPENPROMS info->dki_ctlr = (int) devp->sd_dev->devi_parent->devi_reg->reg_addr; info->dki_unit = (Tgt(devp)<<3)|Lun(devp);#else info->dki_ctlr = getdevaddr(devp->sd_dev->md_mc->mc_addr); info->dki_unit = devp->sd_dev->md_slave;#endif switch (un->un_dp->ctype) { case CTYPE_MD21: info->dki_ctype = DKC_MD21; break;#ifdef ADAPTEC case CTYPE_ACB4000: info->dki_ctype = DKC_ACB4000; break;#endif /* ADAPTEC */ default: info->dki_ctype = DKC_SCSI_CCS; break; } info->dki_flags = DKI_FMTVOL; return (0); case DKIOCGGEOM: /* * Return the geometry of the specified unit. */ *(struct dk_geom *)data = un->un_g; return (0); /* * Set the geometry of the specified unit. */ case DKIOCSGEOM: un->un_g = *(struct dk_geom *)data; return (0); case DKIOCGPART: /* * Return the map for the specified logical partition. * This has been made obsolete by the get all partitions * command. */ *(struct dk_map *)data = *lp; return (0); case DKIOCSPART: /* * Set the map for the specified logical partition. * This has been made obsolete by the set all partitions * command. We raise the priority just to make sure * an interrupt doesn't come in while the map is * half updated. */ *lp = *(struct dk_map *)data; return (0); /* * Return configuration info */ case DKIOCGCONF: conf = (struct dk_conf *)data; switch (un->un_dp->ctype) { case CTYPE_MD21: conf->dkc_ctype = DKC_MD21; break;#ifdef ADAPTEC case CTYPE_ACB4000: conf->dkc_ctype = DKC_ACB4000; break;#endif /* ADAPTEC */ default: conf->dkc_ctype = DKC_MD21; break; } conf->dkc_dname[0] = 's'; conf->dkc_dname[1] = 'd'; conf->dkc_dname[2] = 0; conf->dkc_flags = DKI_FMTVOL;#ifndef OPENPROMS conf->dkc_cnum = devp->sd_dev->md_mc->mc_ctlr; conf->dkc_addr = getdevaddr(devp->sd_dev->md_mc->mc_addr); conf->dkc_space = devp->sd_dev->md_mc->mc_space; conf->dkc_prio = devp->sd_dev->md_mc->mc_intpri; if (devp->sd_dev->md_mc->mc_intr) conf->dkc_vec = devp->sd_dev->md_mc->mc_intr->v_vec; else conf->dkc_vec = 0; (void) strncpy(conf->dkc_cname, devp->sd_dev->md_driver->mdr_cname, DK_DEVLEN); conf->dkc_unit = devp->sd_dev->md_unit; conf->dkc_slave = devp->sd_dev->md_slave;#else OPENPROMS conf->dkc_cnum = devp->sd_dev->devi_parent->devi_unit; conf->dkc_addr = (int) devp->sd_dev->devi_parent->devi_reg->reg_addr; conf->dkc_space = devp->sd_dev->devi_parent->devi_reg->reg_bustype; conf->dkc_prio = ipltospl(devp->sd_dev->devi_parent->devi_intr->int_pri); (void) strcpy(conf->dkc_cname, CNAME); conf->dkc_cname[3] = CUNIT; conf->dkc_unit = unit; conf->dkc_slave = (Tgt(devp)<<3)|Lun(devp);#endif OPENPROMS return (0); /* * Return the map for all logical partitions. */ case DKIOCGAPART: for (i = 0; i < NDKMAP; i++) ((struct dk_map *)data)[i] = un->un_map[i]; return (0); /* * Set the map for all logical partitions. We raise * the priority just to make sure an interrupt doesn't * come in while the map is half updated. */ case DKIOCSAPART: s = splr(sdpri); for (i = 0; i < NDKMAP; i++) un->un_map[i] = ((struct dk_map *)data)[i]; (void) splx(s); return (0); /* * Get error status from last command. */ case DKIOCGDIAG: diag = (struct dk_diag *) data; diag->dkd_errcmd = un->un_last_cmd; diag->dkd_errsect = un->un_err_blkno; diag->dkd_errno = un->un_status; diag->dkd_severe = un->un_err_severe; un->un_last_cmd = 0; /* Reset */ un->un_err_blkno = 0; un->un_err_code = 0; un->un_err_severe = 0; return (0); /* * Run a generic command. */ case DKIOCSCMD: return (sd_maptouscsi(dev, data)); /* * Run a geneeric ucsi.h command. */ case USCSICMD: return (sdioctl_cmd(dev, data, 0)); /* * Handle unknown ioctls here. */ default: return (ENOTTY); }}static intsd_maptouscsi(dev, data)dev_t dev;caddr_t data;{ register struct scsi_device *devp; struct dk_cmd *dcom; struct uscsi_cmd scmd, *ucom = &scmd; char cmdblk[CDB_SIZE], *cdb = cmdblk; u_short cmd; auto daddr_t blkno = 0; int count; int g1 = 0; bzero(cdb, CDB_SIZE); devp = sdunits[SDUNIT(dev)]; dcom = (struct dk_cmd *)data; count = dcom->dkc_buflen; blkno = (daddr_t)dcom->dkc_blkno; cmd = dcom->dkc_cmd; switch (dcom->dkc_cmd) { case SCMD_READ: case SCMD_WRITE: { DPRINTF_IOCTL(devp, "special %s", (dcom->dkc_cmd == SCMD_READ) ? "read" : "write"); if (dcom->dkc_buflen & (SECSIZE-1)) return (EINVAL); count = (count + (SECSIZE - 1)) >> SECDIV; if (dcom->dkc_cmd == SCMD_READ) ucom->uscsi_flags = USCSI_READ; else ucom->uscsi_flags = USCSI_WRITE; if (blkno >= (2<<20) || count > 0xff) { cmd |= SCMD_GROUP1; g1 = 1; } break; } case SCMD_MODE_SELECT: { DPRINTF_IOCTL(devp, "mode select; sp=%d", (blkno & 0x80)? 1 : 0); if (blkno & 0x80) { /* * The 'save parameters' bit * is in the first bit of the 'tag', * or bit #16 of a nominal 21 bit * block address. Unfortunately, 4.0 * format(8) sets bit #7 to indicate * that these are saveable parameters. */ blkno = 0x10000; } else blkno = 0; ucom->uscsi_flags = USCSI_WRITE; break; } case SCMD_MODE_SENSE: { DPRINTF_IOCTL(devp, "mode sense: pcf=0x%x, page 0x%x", blkno>>5, blkno&0x1f); blkno <<= 8; ucom->uscsi_flags = USCSI_READ; break; } case SCMD_READ_DEFECT_LIST: { char descriptor; /* * yet another compatibility deal with 4.0- * we have to pick up the defect list descriptor * from the user's buffer itself. Also, the * Defect List Format stuff will end up in what * is the most significant byte of a 32 byte * block address. */ struct scsi_defect_list *sd = (struct scsi_defect_list *) dcom->dkc_bufaddr; g1 = 1; u.u_error = copyin((caddr_t)&sd->descriptor, &descriptor, 1); if (u.u_error) return (u.u_error); DPRINTF_IOCTL(devp, "read_defect_list: descrip %x", descriptor); blkno = descriptor & 0xff; blkno <<= 24; ucom->uscsi_flags = USCSI_READ; break; } case SCMD_REASSIGN_BLOCK: { /* * Compatibility with 4.0. The block to be * reassigned is in the block field. We * have had to make a little buffer for * it (in the correct format) and we will * then put the block into that little buffer */ DPRINTF_IOCTL(devp, "reassign block %d, count %d (== 8?)", blkno, count); if (devp->sd_inq->inq_rdf < RDF_CCS) { /* reassign block unlikely for non-CCS device */ /* XXX SHOULDN'T WE JUST LET IT BOUNCE THE COMMAND? */ return (EINVAL); } else if (dcom->dkc_buflen) { return (EINVAL); } ucom->uscsi_flags = USCSI_WRITE; /* * Turn the cdb into a Group 1 command, so that the * block number does not get truncated to 20 bits. * This is a little wierd, since no such command * exists for reassign, but we perform the * inverse transformation later, so we're ok. */ cmd |= SCMD_GROUP1; g1 = 1; break; } case SCMD_FORMAT: { DPRINTF_IOCTL(devp, "format: blkno_bits 0x%x", blkno); if (blkno & 0x80000000) { unsigned int tmp; /* * interleave */ tmp = blkno; count = tmp&0xff; blkno = (tmp>>8)&0xff; /* * data pattern */ blkno |= (((tmp>>16)&0xff)<<8); /* * format parameter bits */ blkno |= (((tmp>>24)&0x1f)<<16); } else { blkno = (FPB_DATA|FPB_CMPLT|FPB_BFI)<<16; count = 1; /* interleave */ } ucom->uscsi_flags = USCSI_WRITE; break; } case SCMD_TEST_UNIT_READY: { if (dcom->dkc_buflen) return (EINVAL); ucom->uscsi_flags = USCSI_WRITE; break; } default: return (EINVAL); } if (DEBUGGING_ALL) { sdprintf(devp, "sd_maptouscsi cmd= %x blk= %x buflen= 0x%x", dcom->dkc_cmd, dcom->dkc_blkno, dcom->dkc_buflen); if (ucom->uscsi_flags == USCSI_WRITE && dcom->dkc_buflen) { auto u_int i, amt = min(64, dcom->dkc_buflen); char buf [64]; if (copyin(dcom->dkc_bufaddr, buf, amt)) { return (EFAULT); } printf("\tuser's buf:"); for (i = 0; i < amt; i++) { printf(" 0x%x", buf[i]&0xff); } printf("\n"); } } cmdblk[0] = (u_char)cmd; ucom->uscsi_cdb = cdb; if (g1) { FORMG1ADDR((union scsi_cdb *)cmdblk, blkno);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -