📄 wd.c
字号:
goto exit; }#endif case ATAIOCCOMMAND: /* * Make sure this command is (relatively) safe first */ if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 && (flag & FWRITE) == 0) { error = EBADF; goto exit; } { struct wd_ioctl *wi; atareq_t *atareq = (atareq_t *) addr; int error; wi = wi_get(); wi->wi_softc = wd; wi->wi_atareq = *atareq; if (atareq->datalen && atareq->flags & (ATACMD_READ | ATACMD_WRITE)) { wi->wi_iov.iov_base = atareq->databuf; wi->wi_iov.iov_len = atareq->datalen; wi->wi_uio.uio_iov = &wi->wi_iov; wi->wi_uio.uio_iovcnt = 1; wi->wi_uio.uio_resid = atareq->datalen; wi->wi_uio.uio_offset = 0; wi->wi_uio.uio_segflg = UIO_USERSPACE; wi->wi_uio.uio_rw = (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE; wi->wi_uio.uio_procp = p; error = physio(wdioctlstrategy, &wi->wi_bp, dev, (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE, minphys, &wi->wi_uio); } else { /* No need to call physio if we don't have any user data */ wi->wi_bp.b_flags = 0; wi->wi_bp.b_data = 0; wi->wi_bp.b_bcount = 0; wi->wi_bp.b_dev = 0; wi->wi_bp.b_proc = p; wdioctlstrategy(&wi->wi_bp); error = wi->wi_bp.b_error; } *atareq = wi->wi_atareq; wi_free(wi); goto exit; }#endif /* PMON */ default: error = ENOTTY; goto exit; }#ifdef DIAGNOSTIC panic("wdioctl: impossible");#endif exit: device_unref(&wd->sc_dev); return (error);}#ifdef B_FORMATintwdformat(struct buf *bp){ bp->b_flags |= B_FORMAT; return wdstrategy(bp);}#endifintwdsize(dev) dev_t dev;{ struct wd_softc *wd; int part, omask; int size; WDCDEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS); wd = wdlookup(WDUNIT(dev)); if (wd == NULL) return (-1); part = WDPART(dev); omask = wd->sc_dk.dk_openmask & (1 << part); if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) { size = -1; goto exit; } if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; else size = wd->sc_dk.dk_label->d_partitions[part].p_size * (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0) size = -1; exit: device_unref(&wd->sc_dev); return (size);}#ifndef __BDEVSW_DUMP_OLD_TYPE/* #define WD_DUMP_NOT_TRUSTED if you just want to watch */static int wddoingadump = 0;static int wddumprecalibrated = 0;static int wddumpmulti = 1;/* * Dump core after a system crash. */intwddump(dev, blkno, va, size) dev_t dev; daddr_t blkno; caddr_t va; size_t size;{ struct wd_softc *wd; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; int nblks; /* total number of sectors left to write */ int err; char errbuf[256]; /* Check if recursive dump; if so, punt. */ if (wddoingadump) return EFAULT; wddoingadump = 1; unit = WDUNIT(dev); wd = wdlookup(unit); if (wd == NULL) return ENXIO; part = WDPART(dev); /* Make sure it was initialized. */ if (wd->drvp->state < READY) return ENXIO; /* Convert to disk sectors. Request must be a multiple of size. */ lp = wd->sc_dk.dk_label; if ((size % lp->d_secsize) != 0) return EFAULT; nblks = size / lp->d_secsize; blkno = blkno / (lp->d_secsize / DEV_BSIZE); /* Check transfer bounds against partition size. */ if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) return EINVAL; /* Offset block number to start of partition. */ blkno += lp->d_partitions[part].p_offset; /* Recalibrate, if first dump transfer. */ if (wddumprecalibrated == 0) { wddumpmulti = wd->sc_multi; wddumprecalibrated = 1; wd->drvp->state = RECAL; } while (nblks > 0) {again: wd->sc_wdc_bio.blkno = blkno; wd->sc_wdc_bio.flags = ATA_POLL; if (wddumpmulti == 1) wd->sc_wdc_bio.flags |= ATA_SINGLE; if (wd->sc_flags & WDF_LBA) wd->sc_wdc_bio.flags |= ATA_LBA; wd->sc_wdc_bio.bcount = min(nblks, wddumpmulti) * lp->d_secsize; wd->sc_wdc_bio.databuf = va; wd->sc_wdc_bio.wd = wd;#ifndef WD_DUMP_NOT_TRUSTED switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { case WDC_TRY_AGAIN: panic("wddump: try again"); break; case WDC_QUEUED: panic("wddump: polled command has been queued"); break; case WDC_COMPLETE: break; } switch(wd->sc_wdc_bio.error) { case TIMEOUT: printf("wddump: device timed out"); err = EIO; break; case ERR_DF: printf("wddump: drive fault"); err = EIO; break; case ERR_DMA: printf("wddump: DMA error"); err = EIO; break; case ERROR: errbuf[0] = '\0'; ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf); printf("wddump: %s", errbuf); err = EIO; break; case NOERROR: err = 0; break; default: panic("wddump: unknown error type"); } if (err != 0) { if (wddumpmulti != 1) { wddumpmulti = 1; /* retry in single-sector */ printf(", retrying\n"); goto again; } printf("\n"); return err; }#else /* WD_DUMP_NOT_TRUSTED */ /* Let's just talk about this first... */ printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n", unit, va, cylin, head, sector); delay(500 * 1000); /* half a second */#endif /* update block count */ nblks -= min(nblks, wddumpmulti); blkno += min(nblks, wddumpmulti); va += min(nblks, wddumpmulti) * lp->d_secsize; } wddoingadump = 0; return 0;}#else /* __BDEVSW_DUMP_NEW_TYPE */intwddump(dev, blkno, va, size) dev_t dev; daddr_t blkno; caddr_t va; size_t size;{ /* Not implemented. */ return ENXIO;}#endif /* __BDEVSW_DUMP_NEW_TYPE */#ifdef DKBAD/* * Internalize the bad sector table. */voidbad144intern(wd) struct wd_softc *wd;{ struct dkbad *bt = &DKBAD(wd->sc_dk.dk_cpulabel); struct disklabel *lp = wd->sc_dk.dk_label; int i = 0; WDCDEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS); for (; i < NBT_BAD; i++) { if (bt->bt_bad[i].bt_cyl == 0xffff) break; wd->sc_badsect[i] = bt->bt_bad[i].bt_cyl * lp->d_secpercyl + (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + (bt->bt_bad[i].bt_trksec & 0xff); } for (; i < NBT_BAD+1; i++) wd->sc_badsect[i] = -1;}#endifintwd_get_params(wd, flags, params) struct wd_softc *wd; u_int8_t flags; struct ataparams *params;{ switch (ata_get_params(wd->drvp, flags, params)) { case CMD_AGAIN: return 1; case CMD_ERR: /* * We `know' there's a drive here; just assume it's old. * This geometry is only used to read the MBR and print a * (false) attach message. */ strncpy(params->atap_model, "ST506", sizeof params->atap_model); params->atap_config = ATA_CFG_FIXED; params->atap_cylinders = 1024; params->atap_heads = 8; params->atap_sectors = 17; params->atap_multi = 1; params->atap_capabilities1 = params->atap_capabilities2 = 0; wd->drvp->ata_vers = -1; /* Mark it as pre-ATA */ return 0; case CMD_OK: return 0; default: panic("wd_get_params: bad return code from ata_get_params"); /* NOTREACHED */ }}voidwd_flushcache(wd, flags) struct wd_softc *wd; int flags;{ struct wdc_command wdc_c; if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */ return; bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = WDCC_FLUSHCACHE; wdc_c.r_st_bmask = WDCS_DRDY; wdc_c.r_st_pmask = WDCS_DRDY; wdc_c.flags = flags | AT_WAIT; wdc_c.timeout = 30000; /* 30s timeout */ if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { printf("%s: flush cache command didn't complete\n", wd->sc_dev.dv_xname); } if (wdc_c.flags & AT_TIMEOU) { printf("%s: flush cache command timeout\n", wd->sc_dev.dv_xname); } if (wdc_c.flags & AT_DF) { printf("%s: flush cache command: drive fault\n", wd->sc_dev.dv_xname); } /* * Ignore error register, it shouldn't report anything else * than COMMAND ABORTED, which means the device doesn't support * flush cache */}voidwd_shutdown(arg) void *arg;{ struct wd_softc *wd = arg; wd_flushcache(wd, ATA_POLL);}/* * Allocate space for a ioctl queue structure. Mostly taken from * scsipi_ioctl.c */struct wd_ioctl *wi_get(){ struct wd_ioctl *wi; int s; wi = malloc(sizeof(struct wd_ioctl), M_TEMP, M_WAITOK); bzero(wi, sizeof (struct wd_ioctl)); s = splbio(); LIST_INSERT_HEAD(&wi_head, wi, wi_list); splx(s); return (wi);}/* * Free an ioctl structure and remove it from our list */voidwi_free(wi) struct wd_ioctl *wi;{ int s; s = splbio(); LIST_REMOVE(wi, wi_list); splx(s); free(wi, M_TEMP);}/* * Find a wd_ioctl structure based on the struct buf. */struct wd_ioctl *wi_find(bp) struct buf *bp;{ struct wd_ioctl *wi; int s; s = splbio(); for (wi = wi_head.lh_first; wi != 0; wi = wi->wi_list.le_next) if (bp == &wi->wi_bp) break; splx(s); return (wi);}/* * Ioctl pseudo strategy routine * * This is mostly stolen from scsipi_ioctl.c:scsistrategy(). What * happens here is: * * - wdioctl() queues a wd_ioctl structure. * * - wdioctl() calls physio/wdioctlstrategy based on whether or not * user space I/O is required. If physio() is called, physio() eventually * calls wdioctlstrategy(). * * - In either case, wdioctlstrategy() calls wdc_exec_command() * to perform the actual command * * The reason for the use of the pseudo strategy routine is because * when doing I/O to/from user space, physio _really_ wants to be in * the loop. We could put the entire buffer into the ioctl request * structure, but that won't scale if we want to do things like download * microcode. */voidwdioctlstrategy(bp) struct buf *bp;{ struct wd_ioctl *wi; struct wdc_command wdc_c; int error = 0; wi = wi_find(bp); if (wi == NULL) { printf("user_strat: No ioctl\n"); error = EINVAL; goto bad; } bzero(&wdc_c, sizeof(wdc_c)); /* * Abort if physio broke up the transfer */ if (bp->b_bcount != wi->wi_atareq.datalen) { printf("physio split wd ioctl request... cannot proceed\n"); error = EIO; goto bad; } /* * Abort if we didn't get a buffer size that was a multiple of * our sector size (or was larger than NBBY) */ if ((bp->b_bcount % wi->wi_softc->sc_dk.dk_label->d_secsize) != 0 || (bp->b_bcount / wi->wi_softc->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) { error = EINVAL; goto bad; } /* * Make sure a timeout was supplied in the ioctl request */ if (wi->wi_atareq.timeout == 0) { error = EINVAL; goto bad; } if (wi->wi_atareq.flags & ATACMD_READ) wdc_c.flags |= AT_READ; else if (wi->wi_atareq.flags & ATACMD_WRITE) wdc_c.flags |= AT_WRITE; if (wi->wi_atareq.flags & ATACMD_READREG) wdc_c.flags |= AT_READREG; wdc_c.flags |= AT_WAIT; wdc_c.timeout = wi->wi_atareq.timeout; wdc_c.r_command = wi->wi_atareq.command; wdc_c.r_head = wi->wi_atareq.head & 0x0f; wdc_c.r_cyl = wi->wi_atareq.cylinder; wdc_c.r_sector = wi->wi_atareq.sec_num; wdc_c.r_count = wi->wi_atareq.sec_count; wdc_c.r_precomp = wi->wi_atareq.features; wdc_c.r_st_bmask = WDCS_DRDY; wdc_c.r_st_pmask = WDCS_DRDY; wdc_c.data = wi->wi_bp.b_data; wdc_c.bcount = wi->wi_bp.b_bcount; if (wdc_exec_command(wi->wi_softc->drvp, &wdc_c) != WDC_COMPLETE) { wi->wi_atareq.retsts = ATACMD_ERROR; goto bad; } if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { if (wdc_c.flags & AT_ERROR) { wi->wi_atareq.retsts = ATACMD_ERROR; wi->wi_atareq.error = wdc_c.r_error; } else if (wdc_c.flags & AT_DF) wi->wi_atareq.retsts = ATACMD_DF; else wi->wi_atareq.retsts = ATACMD_TIMEOUT; } else { wi->wi_atareq.retsts = ATACMD_OK; if (wi->wi_atareq.flags & ATACMD_READREG) { wi->wi_atareq.head = wdc_c.r_head ; wi->wi_atareq.cylinder = wdc_c.r_cyl; wi->wi_atareq.sec_num = wdc_c.r_sector; wi->wi_atareq.sec_count = wdc_c.r_count; wi->wi_atareq.features = wdc_c.r_precomp; wi->wi_atareq.error = wdc_c.r_error; } } bp->b_error = 0; biodone(bp); return;bad: bp->b_flags |= B_ERROR; bp->b_error = error; biodone(bp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -