/* * sdremap - tell a SCSI disk to remap the bad block * specified on the command line. * * Compile this on your favorite NetBSD 1.1 system with: * * cc -I/sys -DOLD_SCSI_BYTES -o sdremap sdremap.c * * or on newer NetBSD systems with: * * cc -I/sys -o sdremap sdremap.c * * It will be pretty obvious if you need to add or remove the OLD_SCSI_BYTES * define; this program won't compile if the setting is incorrect. * * When you use this program, make sure the disk you're mucking with * has no mounted filesystems (unless that's just not possible, in which * case, make sure they're mounted read-only, and you're in single-user * mode). You must use the "raw partition" of the disk. On an i386, this * is `d', and everywhere else `c'. * * I.e.: * ./sdremap /dev/rsd1d 356642 * * Written by Jason R. Thorpe . * This program is in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * TODO: * Handle multiple blocks with a single command. I'm just lazy. */ #include #include #include #include #include #include #include #include #include #include #include extern char *__progname; /* from crt0.o */ static void usage __P((void)); static void cleanup __P((void)); static int disk_fd; int main(argc, argv) int argc; char **argv; { struct scsi_reassign_blocks cmd; struct scsi_reassign_blocks_data desc; scsireq_t req; char *disk, *cp; u_int32_t blkno; u_int16_t desc_data_len; if (argc != 3) usage(); disk = argv[1]; blkno = (u_int32_t)strtol(argv[2], &cp, 10); if (*cp != '\0') errx(1, "invalid block number `%s'", argv[2]); /* Register cleanup function. */ if (atexit(cleanup)) err(1, "can't register cleanup function"); /* Open the device... */ if ((disk_fd = open(disk, O_RDWR, 0600)) == -1) err(1, "%s: open", disk); /* Build SCSI command. */ bzero(&cmd, sizeof(cmd)); cmd.opcode = REASSIGN_BLOCKS; /* * Build the block descriptor. */ desc_data_len = sizeof(desc.defect_descriptor[0]); bzero(&desc, sizeof(desc)); /* Descriptor length. */ #ifdef OLD_SCSI_BYTES desc.length_msb = (desc_data_len >> 8) & 0xff; desc.length_lsb = desc_data_len & 0xff; #else desc.length[0] = (desc_data_len >> 8) & 0xff; desc.length[1] = desc_data_len & 0xff; #endif /* Block number. */ #ifdef OLD_SCSI_BYTES desc.defect_descriptor[0].dlbaddr_3 = (blkno >> 24) & 0xff; desc.defect_descriptor[0].dlbaddr_2 = (blkno >> 16) & 0xff; desc.defect_descriptor[0].dlbaddr_1 = (blkno >> 8) & 0xff; desc.defect_descriptor[0].dlbaddr_0 = blkno & 0xff; #else desc.defect_descriptor[0].dlbaddr[0] = (blkno >> 24) & 0xff; desc.defect_descriptor[0].dlbaddr[1] = (blkno >> 16) & 0xff; desc.defect_descriptor[0].dlbaddr[2] = (blkno >> 8) & 0xff; desc.defect_descriptor[0].dlbaddr[3] = blkno & 0xff; #endif /* Fill out user-level SCSI request. */ bzero(&req, sizeof(req)); bcopy((struct scsi_generic *)&cmd, &req.cmd, sizeof(cmd)); req.cmdlen = (u_char)sizeof(cmd); req.databuf = (void *)&desc; req.datalen = (u_long)sizeof(desc); req.flags |= SCCMD_WRITE; req.timeout = 20000; /* XXX */ /* Send the request to the SCSI subsystem. */ if (ioctl(disk_fd, SCIOCCOMMAND, (char *)&req) == -1) err(1, "SCIOCCOMMAND"); /* * XXX should check for error condition and print * sense data. */ exit(0); } static void cleanup() { /* ...simple enough... */ (void)close(disk_fd); } static void usage() { fprintf(stderr, "usage: %s disk blkno\n", __progname); exit(1); }