oldcomp:iomega_zip_jaz

Iomega Zip and Jaz drive notes

This is a collection of arcana on Zip drives you (might not) find anywhere else…

If you have any of these documents, please drop me a line at philpem@gmail.com.

  • Iomega PPA3 Parallel Port SCSI HBA documentation
    • This is apparently quite an old thing which seems to date back to the days of the Bernoulli Box. I expect documentation is quite hard to find!
  • Iomega document EN144302 – title unknown
    • According to comments in the Linux IMM driver, this is the spec for the MatchMaker (IMM) chip which replaced the PPA.
    • From the same source, Iomega would (as of 1998) send this to driver developers.
  • Any Iomega documentation covering Zip or Jaz drive programming, SCSI commands, interfacing, schematics, service manuals… anything more technical than a user's manual.

The Zip and Jaz drives are, by and large, SCSI removable mass storage devices. Somewhat surprisingly this even applies to the parallel-port drives, which have either an PPA3 (Parallel Port Accessory, aka VP0) or MatchMaker (Iomega IMG VP1) chip to convert from SCSI to parallel.

The drive's main processor is an Iomega ASIC – in parallel drives this tends to be a PHAEDRUS chip which talks to an AIC-7110 SCSI controller, while in ATAPI drives it's a RUCIFY chip which talks directly to the IDE bus. An Iomega patent, US5809520A, gives more information on Phaedrus: it contains an 8032 microcontroller core, 1K of RAM and the data encoding/decoding logic.

From there, there's a read-channel IC (ATAPI: TI 34P3410; parallel: IMP 62C538) and a spindle motor driver (ATAPI: TI TLS2247; parallel: Philips TDA5341G) which interface the processor to the drive mechanics. The ASIC has an external firmware ROM – either a 27C512 (parallel drives) or an AT27LV520 (ATAPI drives).

Chip function Zip 100 SCSI External Zip 100 Parallel Zip 100 ATA Zip 100 ATAPI Zip 250 IDE/ATAPI Zip 250MB PC/MAC with PCMCIA option
Board codename ZI5341S (1995) Z5341PI (1996) Zip PPI (1997) :?: :?: ATAPI 250 Sybil
Main ASIC Phaedrus
02430600
Phaethon
02590303
Bruno Rucify
03045005
Bruno
03282001
:?:
Read channel IMP 62C538-136BJ :?: TI 34P3410
Spindle motor driver Philips TDA5341G TI TLS2247
Firmware ROM M27C512 (ST) Atmel AT27LV520
Interface/ASIC? Adaptec AIC-7110Q Adaptec AIC-7110Q
NEC 02415400 IMGVP0
NEC :?: TI 03874600 / F721905PAG
Head amp TI PTS21H52-3 :?:

The internal codename is usually printed on a label attached to the PCB.

Board photos used to derive the table above:

Acknowledgements

This section is based on what I've found by poking and prodding a Zip Plus (hybrid parallel/SCSI) drive with FWB Hard Disk Toolkit, and from the source code of Trouble in Paradise (by Steve Gibson) and parts of the SCSIQuery Amiga utility sources which were sent to me by Thomas Richter.

Thanks also to Martin, for the PowerMac 7300 G3 which DPD turned into a repair project! I'm not sure I could have figured out the gory details of the 2F mode page without it.

These parameters are written with a Mode Select (CMD 15h) CDB like this:

```
 1525 200.088_290_628  CMD - Mode Sel(6) 
                        15 10 00 00 12 00
 1526 200.088_746_876  DataOut (N)
                        00 00 00 08 00 00 00 00 ........
                        00 00 02 00 2F 04 5C 0F ..../.\.
                        FF 0F                   ..
                       (18 Bytes)

CDB:
   Cmd = 15h
   Flags = 10h -- PF=1 (SCSI-3 format)
   Param List Length = 12h = 18 bytes

Mode parameter header(6)
   Mode data length     = 0    (byte 0)
   Medium type          = 0    (byte 1)
   Device-specific      = 0    (byte 2)
   Block Descriptor Len = 8    (byte 3)

Block descriptor:
   Number of blocks     = 0    (bytes 0-3, big endian)
   Reserved             = 0    (byte 4)
   Logical block length = 512  (bytes 5-7, big endian)

Mode page:
   Page code            = 2Fh  (Iomega Zip vendor-specific parameters mode page)  (byte 0)
   Page length          = 4    (byte 1)
   Page data as below -- 4 bytes

Strictly speaking, the mode data length field should be set to 11h (17 decimal) but the FWB software sends a length of zero. I have no idea if the Zip drive requires this, or if it's a bug in FWB's software. Either way, the Zip drive doesn't seem to care.

The current settings may be queried with a Mode Sense (CMD 1Ah) CDB like this:

 1575 203.617_717_096  CMD - Mode Sns(6) 
                        1A 00 2F 00 12 00
 1576 203.618_844_428  DataIn (N)
                        11 00 00 08 00 00 00 00 ........
                        00 00 02 00 2F 04 5C 0F ..../.\.
                        FF 0F                   ..
                       (18 Bytes)

CDB:
   Cmd = 1Ah
   Flags = 00h
   Page code = 2Fh (Iomega Zip vendor-specific parameters); Page Control = 00b (current values)
   Subpage code = 00h
   Param List Length = 12h = 18 bytes

Mode page format

The mode page format is 4 bytes, organised as follows:

ff ss tt uu
  • ff: Flags, see below. (default 0x5C = SCRUB+FTME+RIDI+OFFTR)
  • ss: Spindown timer in minutes, 1 to 255. 0 disables. (default 15)
  • tt: Park timer, 0-255. 0 disables. (default 255)
  • uu: Max read retries, 0-15. (default 15)

The flag bits are as follows:

Bit Mnemonic Function
b0 (LSB) - Always 0
b1 PHSK Physical Seek
b2 OFFTR Off Track
b3 RIDI Read IDs Intelligently
b4 FTME Fault Tolerant Mode Enable
b5 VSC Vendor Specific Commands
b6 SCRUB Head Cleaning on error
b7 (MSB) DHS Disable Head Sweep

The majority of this is from the ReadIOX function in the SCSIQuery source code.

These are accessed with CMD 06 “vendor unique”:

06 ff pp 00 nn 00
  • 06: command code (always 6)
  • ff: Flags (always 0)
  • pp: Page number
    • 1: Format Status (IOPA_DEFECT_DATA)
    • 2: Disk Status (IOPA_DEVICE_DATA)
  • 00: reserved (always 0)
  • nn: Length
  • 00: control (always 0)

Format Status page (IOPA_DEFECT_DATA)

Information about this is from the IOXDefectData structure in the SCSIQuery source code.

:!: TODO: Example data

  * 00..01h: WORD: Count1
  * 02..03h: WORD: Count2
  * 04h:

Disk Status page (IOPA_DEVICE_DATA)

Information about this is from the Trouble In Paradise and SCSIQuery source code (IOXData, JOXData structures).

Old form

Same as New Form but without the two prefix bytes.

Can be identified by checking if the first two bytes are equal to the page number and the length requested less two, e.g. `02 3D`.

New form
  368  46.492_507_276  CMD - Vendor Uniq.
                        06 00 02 00 3F 00
  369  46.493_330_964  DataIn (N)
                    0h: 02 3D 00 02 00 00 02 FF .=......
                    8h: FF 00 00 02 00 00 75 00 ......u.
                   10h: 09 00 7E 00 00 00 31 30 ..~...10
                   18h: 38 31 39 30 34 31 35 30 81904150
                   20h: 32 39 36 31 39 38 30 32 29619802
                   28h: 5A 49 50 20 20 20 20 4B ZIP    K
                   30h: 41 4D 30 37 20 20 20 20 AM07    
                   38h: 20 20 20 20 20 20 01          .
                       (63 Bytes)
```

  * 00h:     BYTE. Page number
  * 01h:     BYTE. Data length
  * 02..03:  WORD. :?:
  * 04:      BYTE. :?:
  * 05..08h: DWORD. Maximum LBA. (= 0x0002FFFF)
  * 09..0Ch: DWORD. Block size.  (= 512)
  * 0D..0Eh: WORD. Side 0 remaining spares count
  * 0F..10h: WORD. Side 0 bad sectors count
  * 11..12h: WORD. Side 1 remaining spares count
  * 13..14h: WORD. Side 1 bad sectors count
  * 15h:     BYTE. Protection status

The following are seemingly only present in the New Style Mode Page, on Zip Plus and Jaz drives

  * 16..27h: CHAR[18]. Cartridge serial number?  (DiskID)
  * 28..2Eh: CHAR[7].  Cartridge type?  (DiskType)
  * 2F..3Dh: CHAR[15]. Date code?  (VendorCode)
  * 3Eh:     BYTE. Count1

Jaz drives also include the following:

  * 3Fh:     BYTE. Count2
  * 40..41h: WORD: Jaz reserved.
  * 42..43h: WORD: Jaz format life
  * 44..45h: WORD: Jaz disk life

Calculating disk life (Zip disks)

This requires both the IOPA_DEVICE_DATA and IOPA_DEFECT_DATA pages to be read in.

First do some pre-calculations:

DeviceDataStruct ioxdata;
DefectDataStruct ioxdd;
 
Spare1 = ioxdata->Free0;
Spare2 = ioxdata->Free1;
Bad1 = ioxData->Bad0;
Bad2 = ioxdata->Bad1;
 
ioTotal1 = ioxdd->TotalCount;
ioGood1 = ioxdd->OKCount;
 
if (ioxdd->BadFlag) {
  // extra data present for other side
  ioTotal2 = ioxdd->Total2Count;
  ioGood2  = ioxdd->OK2Count;
} else {
  // data is collapsed into one field
  ioTotal2 = ioxdd->TotalCount;
  ioGood2  = ioxdd->OKCount;
}
 
if (ioTotal1 < ioTotal2) {
  ioTotal2 = ioTotal1;
}
if (ioGood1 < ioGood2) {
  ioGood2 = ioGood1;
}

Calculate the disk life:

int diskLife, div;
 
diskLife = ioGood2 + ioTotal2 - Bad1 - Bad2;
div = ioGood1 + ioTotal1;
if (div) {
  disklife = (disklife * 100) / div;
} else {
  disklife = 0;
}
 
Calculate the format life:
 
<code c>
if (Spare1 > Spare2) {
  format = ioSpare2 * 100;
  div = ioSpare2 + Bad2;
} else {
  format = ioSpare1 * 100;
}

Calculating disk life (Jaz disks)

Disk Life (as a percentage) can be calculated with:

DiskLife = (joxData->DiskLife * 100) / 2556;

Format life (as a percentage) is a little trickier:

int format = 0xFF - joxData->FormatLife;
 
if (format < 0) {
  format = 0;
} else {
  format = (format * 100) / 255;
}

Now isn't that easier than Zip disks?

TBD.

Find me on Mastodon
  • Last modified: 2025/02/19 21:33
  • by philpem