Subject: Floptical support

From: "Andreas E. Heitmann" <[email-masked]>

Hi BSDers !

I just hacked a patch to make Floptical drives usable under
NetBSD. Currently this is tested with the IOMEGA Io20S Floptical, but
it should work with the Insite Floptical, too.

It works by requesting the vendor page 0x2E with the MODE_SENSE
command to unlock the drive (make it writable) and rezeroing it before
the first READ command takes place.

The patches are for the #744 versions of files sd.c and scsi.c. I
added routines for requesting a a mode page and to issue a REWIND
command to a unit (did you ever rewind your harddisk ? ;)) There is
also some debug code left in the functions, you can leave it out.

To try the patch with the Insite Floptical, you have to fix the vendor
and device IDs in sdinit.c, because I don't know them for the
Insite. If you have a Insite Floptical, please report back these IDs.

Ok, here we go...

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

*** sd.c	Sun Jan 16 15:11:44 1994
--- /usr/src/sys/arch/amiga/dev/sd.c	Fri Feb 18 05:30:30 1994
***************
*** 79,84 ****
--- 79,85 ----
  extern int sdioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
  extern int sdsize (dev_t dev);
  extern int sddump (dev_t dev);
+ extern int  scsi_unlock_floptical(int ctlr, int slave, int unit);
  static int sdident (struct sd_softc *sc, struct amiga_device *ad);
  static void sdlblkstrat (register struct buf *bp, register int bsize);
  static int sderror (int unit, register struct sd_softc *sc, register struct amiga_device *am, int stat);
***************
*** 352,357 ****
--- 353,377 ----
  		sc->sc_blks <<= sc->sc_bshift;
  	}
  	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
+ 	
+ 
+ 	/* unlock FLOPTICAL */
+ 
+ 	if (!bcmp(&sc->sc_idstr[0],"IOMEGA",6) &&
+ 	    !bcmp(&sc->sc_idstr[8],"Io20S",5)) {
+ 		int stat;
+ 
+ 		printf("Floptical drive detected, trying to unlock...");
+ 		stat=scsi_unlock_floptical(ctlr,slave,unit);
+ 		if(stat!=0) {
+ 			printf("unlock failed: %d\n",stat);
+ 			sderror(unit,sc,sc->sc_ad,stat);
+ 		}
+ 		else {
+ 			printf("success.\n");
+ 		}
+ 	}
+ 
  	scsi_delay(0);
  	return(inqbuf.type);
  failed:
***************
*** 424,430 ****
  	  {
  	    if (scsi_tt_read (ad->amiga_ctlr, ad->amiga_slave, sc->sc_punit,
  			      (char *) block, DEV_BSIZE, bnum, sc->sc_bshift))
- 	      /* read error on block */
  	      goto no_rdb;
  
  	    if (rdb->rdb_ID == IDNAME_RIGIDDISK)
--- 444,449 ----
***************
*** 827,833 ****
  		printf("sd%d: scsi sense class %d, code %d", unit,
  			sp->class, sp->code);
  		if (sp->class == 7) {
! 			printf(", key %d", sp->key);
  			if (sp->valid)
  				printf(", blk %d", *(int *)&sp->info1);
  			switch (sp->key) {
--- 846,857 ----
  		printf("sd%d: scsi sense class %d, code %d", unit,
  			sp->class, sp->code);
  		if (sp->class == 7) {
! 			printf(", key %d",sp->key);
! 			if(sp->len>=6) {
! 			  printf(", sensecode %d, sensequal %d",
! 				 (sdsense[unit].sense)[12],
! 				 (sdsense[unit].sense)[13]);
! 			}
  			if (sp->valid)
  				printf(", blk %d", *(int *)&sp->info1);
  			switch (sp->key) {

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

*** scsi.c	Sat Jan  1 16:52:19 1994
--- /usr/src/sys/arch/amiga/dev/scsi.c	Fri Feb 18 05:20:01 1994
***************
*** 77,84 ****
  static int scsiicmd (struct scsi_softc *dev, int target, u_char *cbuf, int clen, u_char *buf, int len, u_char xferphase);
  static void finishxfer (struct scsi_softc *dev, register volatile sbic_padded_regmap_t *regs, int target);
  static int check_dma_buf (char *buffer, u_long len);
  
- 
  /*
   * SCSI delays
   * In u-seconds, primarily for state changes on the SPC.
--- 77,85 ----
  static int scsiicmd (struct scsi_softc *dev, int target, u_char *cbuf, int clen, u_char *buf, int len, u_char xferphase);
  static void finishxfer (struct scsi_softc *dev, register volatile sbic_padded_regmap_t *regs, int target);
  static int check_dma_buf (char *buffer, u_long len);
+ static int scsi_mode_sense(int ctlr, int slave, int unit, int page, u_char *buf, unsigned len);
+ static int scsi_rezero_unit(int ctlr, int slave, int unit);
  
  /*
   * SCSI delays
   * In u-seconds, primarily for state changes on the SPC.
***************
*** 186,192 ****
  }
  
  /* default to not inhibit sync negotiation on any drive */
! u_char inhibit_sync[NSCSI][8] = { 1, 1, 1, 1, 1, 1, 1 }; /* initialize, so patchable */
  int scsi_no_dma = 0;
  
  #ifdef DEBUG
--- 187,193 ----
  }
  
  /* default to not inhibit sync negotiation on any drive */
! u_char inhibit_sync[NSCSI][8] = { 1, 1, 1, 1, 0, 0, 0 }; /* initialize, so patchable */
  int scsi_no_dma = 0;
  
  #ifdef DEBUG
***************
*** 1291,1296 ****
--- 1292,1322 ----
  }
  
  int
+ scsi_mode_sense(ctlr, slave, unit, page, buf, len)
+ 	int ctlr, slave, unit;
+         int page;
+ 	u_char *buf;
+ 	unsigned len;
+ {
+ 	register struct scsi_softc *dev = &scsi_softc[ctlr];
+ 	static struct scsi_cdb6 cdb = { CMD_MODE_SENSE };
+ 	cdb.lun = unit;  /* we do not disable the block descriptor */
+ 	cdb.lbam= page;
+ 	cdb.len = len;
+ 	return (scsiicmd(dev, slave, (u_char *)&cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));
+ }
+ 
+ int
+ scsi_rezero_unit(ctlr, slave, unit)
+ 	int ctlr, slave, unit;
+ {
+ 	register struct scsi_softc *dev = &scsi_softc[ctlr];
+ 	static struct scsi_cdb6 cdb = { CMD_REWIND };
+ 	cdb.lun = unit;
+ 	return (scsiicmd(dev, slave, (u_char *)&cdb, sizeof(cdb), (char *)0,0, STATUS_PHASE));
+ }
+ 
+ int
  scsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd)
  	int ctlr, slave, unit;
  	struct scsi_fmt_cdb *cdb;
***************
*** 1303,1308 ****
--- 1329,1412 ----
  	return (scsiicmd(dev, slave, (u_char *) cdb->cdb, cdb->len, buf, len,
  			 rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE));
  }
+ 
+ /*
+  * scsi_unlock_floptical() 
+  *
+  * Unlocks a floptical drive by reading the vendor
+  * mode page 0x2e (floptical page). In addition a rezero 
+  * unit command is issued, because the first READ command
+  * fails with a "Servo Hardware Fault" error 
+  * (ASC=2,ASCQ=0). The rezero command will also fail, but
+  * now we can ignore it.
+  */
+ int
+ scsi_unlock_floptical(ctlr, slave, unit)
+      int ctlr;
+      int slave;
+      int unit;
+ {
+   struct mp_header_s {
+     u_char mode_data_length;
+     u_char media_type;
+     u_char block_descriptor_length;
+   };
+ 
+   struct mp_descriptor_s {
+     u_char reserved[4];
+     u_char block_length[4];
+   };
+ 
+   struct floppage_s {
+     u_char reserved1:1,
+            pagecode:7;
+     u_char len;
+     u_char reserved2;
+     u_char hamheads;
+     u_char secpertrack;
+     u_short bytespersector;
+     u_short hamcyls;
+     u_char reserved3:4,
+            ejm:1,
+            reserved4:2,
+            nhf:1;
+     u_char idstr[13];
+     u_char reserved5[6];
+   };
+ 
+   struct sense_return_s {
+     struct mp_header_s mp_header;
+     struct mp_descriptor_s mp_descriptor;
+     struct floppage_s floppage;
+   } sr;
+ 
+   int stat;
+ 
+   stat=scsi_mode_sense(ctlr,slave,unit,0x2e,(u_char *)&sr,sizeof(sr));
+ 
+ #ifdef DEBUG
+   if(stat==0) { /* print some information in the floptical page */
+     printf("Floptical information\n");
+     printf("Page code          : %d\n",sr.floppage.pagecode);
+     printf("Page length        : %d\n",sr.floppage.len);
+     printf("Number of HAM heads: %d\n",sr.floppage.hamheads);
+     printf("Sectors per Track  : %d\n",sr.floppage.secpertrack);
+     printf("Data Bytes/Sector  : %d\n",sr.floppage.bytespersector);
+     printf("Number of HAM cyls : %d\n",sr.floppage.hamcyls);
+     printf("Eject Motor        : %d\n",sr.floppage.ejm);
+     printf("Non-HAM format     : %d\n",sr.floppage.nhf);
+     printf("IdString           : %s\n",sr.floppage.idstr);
+   }
+ #endif
+ 
+   if(stat==0) {
+     stat=scsi_rezero_unit(ctlr,slave,unit);
+     if(stat==2) stat=0; /* explicitly ignore servo fault errors */
+   }
+   return stat;
+ }
+ 
+ 
  
  /*
   * The following routines are test-and-transfer i/o versions of read/write

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

That's it.

Bye,

	Andreas Heitmann ([email-masked])