Subject: Re: SCSI reassign ioctl.
To: Brian Buhrow <buhrow@cats.ucsc.edu>
From: Tobias Weingartner <weingart@austin.BrandonU.CA>
List: current-users
Date: 05/11/1995 13:35:50
In message <199505092315.QAA08014@baloo.ucsc.edu>, Brian Buhrow writes:
> 
> 1.  My understanding is that the scsi system can operate in two modes.  A.
> Automatic correction mode, and B.  Manual correction mode.  In A, the scsi
> disk automatically moves bad sectors to good portions of the disk as the
> errors are discovered.  In the second mode, scsi operations on a bad block
> will continue to try and use the bad block until the scsi system is
> explicitly told not to, either by locking the sector out, or by remapping
> it to a new portion of the physical disk.  In which mode does the netbsd
> scsi subsystem operate?

I believe it uses the first case.  At least NetBSD-1.0 seemed to, last time
I took a look at this code.


> 2.  Even if the netbsd scsi system operates in the automatic mode, is it
> possible to explicitly give scsi commands to remap sectors of hard disks
> through an ioctl interface?

Well, since you have code, most anything is possible! ;-)
On a more serious note, I needed to remap some bad blocks on my root drive,
and could not think of any other way to do it.  I patched a 1.0 kernel, to
give me the ioctl (the code to remap is in there), and then wrote a bare-
bones program to remap the blocks.  The patches are attached


> 3.  Even if it is possible, is the ability to reassign bad blocks an
> extension to the scsi spec which only some controllers are capable of
> handling?  

>From reading the scsi-spec, it is not the controller that needs to
understand, but the disk drive.

PS: If you use the following code, all standard disclaimers apply.  Also,
remap each bad sector only *ONCE*, otherwise you will be remapping the
good sector put in place of the bad one the second time 'round.

--Toby.
*----------------------------------------------------------------------------*
| Tobias Weingartner | Email: weingart@BrandonU.Ca | Need a Unix sys-admin?  |
| Box 27, Beulah, MB |-----------------------------| Send E-Mail for resume, |
| R0M 0B0, Canada    | Unix Guru, Admin, Sys-Prgmr | and other details...    |
|----------------------------------------------------------------------------|
|      %SYSTEM-F-ANARCHISM, The operating system has been overthrown         |
*----------------------------------------------------------------------------*

natasha% rcsdiff -c !$
rcsdiff -c disklabel.h
===================================================================
RCS file: RCS/disklabel.h,v
retrieving revision 1.1
diff -c -r1.1 disklabel.h
*** 1.1 1995/04/12 06:49:53
--- disklabel.h 1995/04/12 06:51:57
***************
*** 369,374 ****
--- 369,376 ----
  
  #define DIOCSBAD      _IOW('d', 110, struct dkbad)    /* set kernel dkbad */
  
+ #define DIOCREASSIGN  _IOW('d', 111, int) /* reassign block */
+ 
  #ifdef KERNEL
  #ifdef i386
  int bounds_check_with_label __P((struct buf *, struct disklabel *, int));
natasha% rcsdiff -c sd.c
===================================================================
RCS file: RCS/sd.c,v
retrieving revision 1.1
diff -c -r1.1 sd.c
*** 1.1 1995/04/12 06:41:58
--- sd.c        1995/04/12 21:27:39
***************
*** 612,617 ****
--- 612,622 ----
                        return error;
                }
  
+       case DIOCREASSIGN: {
+               int blockno = *(int *)addr;
+               return(sd_reassign_blocks(sd, blockno));
+               }
+ 
        default:
                if (part != RAW_PART)
                        return ENOTTY;
natasha% diff -c /dev/null reass.c
*** /dev/null   Thu May 11 02:02:29 1995
--- reass.c     Wed Apr 12 15:59:42 1995
***************
*** 0 ****
--- 1,61 ----
+ /*
+  * $Id$
+  */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <strings.h>
+ #include <unistd.h>
+ #include <err.h>
+ #include <fcntl.h>
+ #include <sys/disklabel.h>
+ #include <sys/types.h>
+ #include <sys/ioctl.h>
+ 
+ int usage(const char* prog){
+       const char *s = strrchr(prog, '/');
+ 
+       if(s == NULL) s = prog;
+       (void)fprintf(stderr, "usage: %s <-f device> <blockno>\n", s);
+       return(1);
+ }
+ 
+ 
+ int main(int argc, char *argv[]){
+       int fd, ch;
+       int blockno = -1;
+       char *dev = NULL;
+ 
+ 
+       /* Get options */
+       while ((ch = getopt(argc, argv, "f:")) != EOF){
+               switch (ch) {
+               case 'f':
+                       dev = optarg;
+                       break;
+               case '?':
+               default:
+                       return(usage(argv[0]));
+               }
+       }
+       blockno = atoi(argv[optind]);
+ 
+       /* Check arguments */
+       if(argc - optind < 1) return(usage(argv[0]));
+       if(blockno == -1 || dev == NULL) return(usage(argv[0]));
+ 
+       /* Fix arguments
+       argc -= optind;
+       argv += optind;
+       */
+ 
+       /* Now do the funky stuff */
+       if((fd = open(dev, O_RDONLY)) < 0) perror("open");
+       if(ioctl(fd, DIOCREASSIGN, &blockno)) warn("CDIOREASSIGN");
+ 
+       /* Close and clean up */
+       close(fd);
+ 
+       return(0);
+ }
+