📄 sd.c
字号:
int s; SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy ")); SC_DEBUG(sd->sc_link, SDEV_DB1, ("%ld bytes @ blk %d\n", bp->b_bcount, bp->b_blkno)); /* * The transfer must be a whole number of blocks. */ if ((bp->b_bcount % sd->sd_secsize) != 0) { bp->b_error = EINVAL; goto bad; } /* * If the device has been made invalid, error out */ if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; goto bad; } /* * If it's a null transfer, return immediatly */ if (bp->b_bcount == 0) goto done; s = splbio(); /* * Place it in the queue of disk activities for this disk */ disksort(&sd->buf_queue, bp); /* * Tell the device to get going on the transfer if it's * not doing anything, otherwise just wait for completion */ sdstart(sd); splx(s); return;bad: bp->b_flags |= B_ERROR;done: /* * Correctly set the buf to indicate a completed xfer */ bp->b_resid = bp->b_bcount; biodone(bp);}/* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It dequeues the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (sdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. * * must be called at the correct (highish) spl level * sdstart() is called at splbio from sdstrategy and scsi_done */void sdstart(v) register void *v;{ register struct sd_softc *sd = v; register struct scsi_link *sc_link = sd->sc_link; struct buf *bp = 0; struct buf *dp; struct scsi_rw_big cmd_big; struct scsi_rw cmd_small; struct scsi_generic *cmdp; int blkno, nblks, cmdlen, error; SC_DEBUG(sc_link, SDEV_DB2, ("sdstart ")); /* * Check if the device has room for another command */ while (sc_link->openings > 0) { /* * there is excess capacity, but a special waits * It'll need the adapter as soon as we clear out of the * way and let it run (user level wait). */ if (sc_link->flags & SDEV_WAITING) { sc_link->flags &= ~SDEV_WAITING; wakeup((caddr_t)sc_link); return; } /* * See if there is a buf with work for us to do.. */ dp = &sd->buf_queue; if ((bp = dp->b_actf) == NULL) /* yes, an assign */ return; dp->b_actf = bp->b_actf; /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); continue; } /* * We have a buf, now we should make a command * * First, translate the block to absolute and put it in terms * of the logical blocksize of the device. */ blkno = bp->b_blkno / (sd->sd_secsize / DEV_BSIZE); nblks = howmany(bp->b_bcount, sd->sd_secsize); /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) { /* * We can fit in a small cdb. */ bzero(&cmd_small, sizeof(cmd_small)); cmd_small.opcode = (bp->b_flags & B_READ) ? READ_COMMAND : WRITE_COMMAND; _lto3b(blkno, cmd_small.addr); cmd_small.length = nblks & 0xff; cmdlen = sizeof(cmd_small); cmdp = (struct scsi_generic *)&cmd_small; } else { /* * Need a large cdb. */ bzero(&cmd_big, sizeof(cmd_big)); cmd_big.opcode = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG; _lto4b(blkno, cmd_big.addr); _lto2b(nblks, cmd_big.length); cmdlen = sizeof(cmd_big); cmdp = (struct scsi_generic *)&cmd_big; } /* * Call the routine that chats with the adapter. * Note: we cannot sleep as we may be an interrupt */ error = scsi_scsi_cmd(sc_link, cmdp, cmdlen, (u_char *)bp->b_data, bp->b_bcount, SDRETRIES, 60000, bp, SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)); if (error) { printf("%s: not queued, error %d\n", sd->sc_dev.dv_xname, error); } }}voidsddone(xs) struct scsi_xfer *xs;{}intsdread(dev, uio, ioflag) dev_t dev; struct uio *uio; int ioflag;{ return (physio(sdstrategy, NULL, dev, B_READ, NULL, uio));}intsdwrite(dev, uio, ioflag) dev_t dev; struct uio *uio; int ioflag;{ return (physio(sdstrategy, NULL, dev, B_WRITE, NULL, uio));}static intsd_mode_sense(sd, scsi_sense, page, flags) struct sd_softc *sd; struct scsi_mode_sense_data *scsi_sense; int page, flags;{ struct scsi_mode_sense scsi_cmd; /* * Make sure the sense buffer is clean before we do * the mode sense, so that checks for bogus values of * 0 will work in case the mode sense fails. */ bzero(scsi_sense, sizeof(*scsi_sense)); bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.opcode = MODE_SENSE; scsi_cmd.page = page; scsi_cmd.length = 0x20; /* * If the command worked, use the results to fill out * the parameter structure */ return scsi_scsi_cmd(sd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), (u_char *)scsi_sense, sizeof(*scsi_sense), SDRETRIES, 6000, NULL, flags | SCSI_DATA_IN | SCSI_SILENT);}intsd_get_optparms(sd, flags, dp) struct sd_softc *sd; int flags; struct disk_parms *dp;{ struct scsi_mode_sense scsi_cmd; struct scsi_mode_sense_data { struct scsi_mode_header header; struct scsi_blk_desc blk_desc; union disk_pages pages; } scsi_sense; u_long sectors; int error; dp->blksize = DEV_BSIZE; if ((sectors = scsi_size(sd->sc_link, flags)) == 0) return 1; /* XXX * It is better to get the following params from the * mode sense page 6 only (optical device parameter page). * However, there are stupid optical devices which does NOT * support the page 6. Ghaa.... */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.opcode = MODE_SENSE; scsi_cmd.page = 0x3f; /* all pages */ scsi_cmd.length = sizeof(struct scsi_mode_header) + sizeof(struct scsi_blk_desc); if ((error = scsi_scsi_cmd(sd->sc_link, (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), (u_char *)&scsi_sense, sizeof(scsi_sense), SDRETRIES, 6000, NULL, flags | SCSI_DATA_IN)) != 0) return error; dp->blksize = _3btol(scsi_sense.blk_desc.blklen); if (dp->blksize == 0) dp->blksize = DEV_BSIZE; /* * Create a pseudo-geometry. */ dp->heads = 64; dp->sectors = 32; dp->cyls = sectors / (dp->heads * dp->sectors); dp->disksize = sectors; return 0;}/* * Get the scsi driver to send a full inquiry to the * device and use the * results to fill out the disk parameter structure. */intsd_get_parms(sd, flags) struct sd_softc *sd; int flags;{ struct disk_parms *dp = &sd->params; struct scsi_mode_sense_data scsi_sense; u_long sectors; int page; int error; if (sd->type == T_OPTICAL) { if ((error = sd_get_optparms(sd, flags, dp)) != 0) sd->sc_link->flags &= ~SDEV_MEDIA_LOADED; return error; } if ((error = sd_mode_sense(sd, &scsi_sense, page = 4, flags)) == 0) { SC_DEBUG(sd->sc_link, SDEV_DB3, ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", _3btol(scsi_sense.pages.rigid_geometry.ncyl), scsi_sense.pages.rigid_geometry.nheads, _2btol(scsi_sense.pages.rigid_geometry.st_cyl_wp), _2btol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), _2btol(scsi_sense.pages.rigid_geometry.land_zone))); /* * KLUDGE!! (for zone recorded disks) * give a number of sectors so that sec * trks * cyls * is <= disk_size * can lead to wasted space! THINK ABOUT THIS ! */ dp->heads = scsi_sense.pages.rigid_geometry.nheads; dp->cyls = _3btol(scsi_sense.pages.rigid_geometry.ncyl); dp->blksize = _3btol(scsi_sense.blk_desc.blklen); if (dp->heads == 0 || dp->cyls == 0) goto fake_it; if (dp->blksize == 0) dp->blksize = DEV_BSIZE; sectors = scsi_size(sd->sc_link, flags); dp->disksize = sectors; sectors /= (dp->heads * dp->cyls); dp->sectors = sectors; /* XXX dubious on SCSI */ return 0; } if ((error = sd_mode_sense(sd, &scsi_sense, page = 5, flags)) == 0) { dp->heads = scsi_sense.pages.flex_geometry.nheads; dp->cyls = _2btol(scsi_sense.pages.flex_geometry.ncyl); dp->blksize = _3btol(scsi_sense.blk_desc.blklen); dp->sectors = scsi_sense.pages.flex_geometry.ph_sec_tr; dp->disksize = dp->heads * dp->cyls * dp->sectors; if (dp->disksize == 0) goto fake_it; if (dp->blksize == 0) dp->blksize = DEV_BSIZE; return 0; }fake_it: if ((sd->sc_link->quirks & SDEV_NOMODESENSE) == 0) { if (error == 0) printf("%s: mode sense (%d) returned nonsense", sd->sc_dev.dv_xname, page); else printf("%s: could not mode sense (4/5)", sd->sc_dev.dv_xname); printf("; using fictitious geometry\n"); } /* * use adaptec standard fictitious geometry * this depends on which controller (e.g. 1542C is * different. but we have to put SOMETHING here..) */ sectors = scsi_size(sd->sc_link, flags); dp->heads = 64; dp->sectors = 32; dp->cyls = sectors / (64 * 32); dp->blksize = DEV_BSIZE; dp->disksize = sectors; return 0;}/* * Copy up to len chars from src to dst, ignoring non-printables. * Must be room for len+1 chars in dst so we can write the NUL. * Does not assume src is NUL-terminated. */voidviscpy(dst, src, len) u_char *dst; u_char *src; int len;{ while (len > 0 && *src != '\0') { if (*src < 0x20 || *src >= 0x80) { src++; continue; } *dst++ = *src++; len--; } *dst = '\0';}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -