153901Smckusick /*
263307Sbostic * Copyright (c) 1992, 1993
363307Sbostic * The Regents of the University of California. All rights reserved.
453901Smckusick *
553901Smckusick * This code is derived from software contributed to Berkeley by
653901Smckusick * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
753901Smckusick *
853901Smckusick * %sccs.include.redist.c%
953901Smckusick *
1053901Smckusick * from: $Hdr: sd.c,v 4.300 91/06/27 20:42:56 root Rel41 $ SONY
1153901Smckusick *
12*64628Sbostic * @(#)sd.c 8.2 (Berkeley) 09/23/93
1353901Smckusick */
1453901Smckusick #define dkblock(bp) bp->b_blkno
1553901Smckusick
1653901Smckusick /*
1753901Smckusick * Copyright (c) 1987-1991 by SONY Corporation.
1853901Smckusick */
1953901Smckusick
2053901Smckusick #include "sd.h"
2153901Smckusick #if NSD > 0
2253901Smckusick
2357182Sutashiro #include <sys/param.h>
2457182Sutashiro #include <sys/buf.h>
2557182Sutashiro #include <sys/proc.h>
2657182Sutashiro #include <sys/user.h>
2757182Sutashiro #include <sys/dkstat.h>
2857182Sutashiro #include <sys/uio.h>
2957182Sutashiro #include <sys/kernel.h>
3057182Sutashiro #include <sys/reboot.h>
3157182Sutashiro #include <sys/ioctl.h>
3257182Sutashiro #include <sys/systm.h>
3357182Sutashiro #include <sys/mtio.h>
3457182Sutashiro #include <sys/stat.h>
3557182Sutashiro #include <sys/disklabel.h>
3657182Sutashiro #include <vm/vm.h>
3757182Sutashiro #include <sys/syslog.h>
3853901Smckusick
3957182Sutashiro #include <ufs/ffs/fs.h>
4053901Smckusick
4157182Sutashiro # include <machine/cpu.h>
4253901Smckusick
4353901Smckusick #ifdef IPC_MRX
4453901Smckusick # include "../iop/iopvar.h"
4553901Smckusick # include "../ipc/newsipc.h"
4653901Smckusick #endif
4753901Smckusick
4853901Smckusick #ifdef CPU_SINGLE
4957182Sutashiro # include <news3400/hbdev/hbvar.h>
5057182Sutashiro # include <news3400/iodev/ioptohb.h>
5153901Smckusick #endif
5253901Smckusick
5357182Sutashiro #include <news3400/iodev/scsireg.h>
5457182Sutashiro #include <news3400/iodev/scu.h>
5557182Sutashiro #include <news3400/iodev/dkio.h>
5657182Sutashiro #include <news3400/iodev/sdreg.h>
5753901Smckusick
5853901Smckusick #define sce_sdecode sce_hdecode
5953901Smckusick
6053901Smckusick #define dev2unit(x) ((minor(x) & ~0x80) >> 3)
6153901Smckusick #define dev2part(x) (minor(x) & 0x7)
6253901Smckusick
6353901Smckusick /* /sys/sys/file.h */
6453901Smckusick #define FREAD 00001 /* descriptor read/receive'able */
6553901Smckusick #define FWRITE 00002 /* descriptor write/send'able */
6653901Smckusick
6753901Smckusick #define PART_A 0
6853901Smckusick #define PART_B 1
6953901Smckusick #define PART_C 2
7053901Smckusick #define PART_D 3
7153901Smckusick #define PART_E 4
7253901Smckusick #define PART_F 5
7353901Smckusick #define PART_G 6
7453901Smckusick #define PART_H 7
7553901Smckusick
7653901Smckusick #define MAXPROBERETRY 100
7753901Smckusick #define NRETRY 10
7853901Smckusick #define MAXHRDERR 100
7953901Smckusick #define MAXRETRYCNT 16
8053901Smckusick
8153901Smckusick #define SDBSIZE1K (DEV_BSIZE * 2)
8253901Smckusick #define MAXSDPHYS ((NSCMAP - 1) * NBPG)
8353901Smckusick
8453901Smckusick #define D100MSEC 100000
8553901Smckusick
8653901Smckusick #if OD_STOPTIME < 1
8753901Smckusick # define OD_STOPTIME 5
8853901Smckusick #endif /* OD_STOPTIME < 1 */
8953901Smckusick
9053901Smckusick #define FORMAT_MODE_CORRUPTED 0x31
9153901Smckusick #define ONLY_ONE 1
9253901Smckusick
9353901Smckusick /************** PARTITIONS *************************************/
9453901Smckusick
9553901Smckusick #define PART_UNUSED (0)
9653901Smckusick #define PART_SPEC (-1)
9753901Smckusick #define PART_CALCF (-2)
9853901Smckusick #define PART_CALCG (-3)
9953901Smckusick
10053901Smckusick struct defpart {
10153901Smckusick int range_min;
10253901Smckusick int range_max;
10353901Smckusick int partsize[PNUM];
10453901Smckusick };
10553901Smckusick
10653901Smckusick struct defpart defpart_std[] = {
10753901Smckusick {
10853901Smckusick 0, /* range_min */
10953901Smckusick 20, /* range_max */
11053901Smckusick
11153901Smckusick PART_SPEC, /* A: */
11253901Smckusick PART_UNUSED, /* B: */
11353901Smckusick PART_SPEC, /* C: */
11453901Smckusick PART_UNUSED, /* D: */
11553901Smckusick PART_UNUSED, /* E: */
11653901Smckusick PART_UNUSED, /* F: */
11753901Smckusick PART_UNUSED, /* G: */
11853901Smckusick PART_UNUSED, /* H: */
11953901Smckusick },
12053901Smckusick {
12153901Smckusick 20, /* range_min */
12253901Smckusick 61, /* range_max */
12353901Smckusick
12453901Smckusick 15884, /* A: */
12553901Smckusick 10032, /* B: */
12653901Smckusick PART_SPEC, /* C: */
12753901Smckusick 15884, /* D: */
12853901Smckusick PART_UNUSED, /* E: */
12953901Smckusick PART_CALCF, /* F: */
13053901Smckusick PART_CALCG, /* G: */
13153901Smckusick PART_UNUSED, /* H: */
13253901Smckusick },
13353901Smckusick {
13453901Smckusick 61, /* range_min */
13553901Smckusick 206, /* range_max */
13653901Smckusick
13753901Smckusick 15884, /* A: */
13853901Smckusick 33440, /* B: */
13953901Smckusick PART_SPEC, /* C: */
14053901Smckusick 15884, /* D: */
14153901Smckusick 55936, /* E: */
14253901Smckusick PART_CALCF, /* F: */
14353901Smckusick PART_CALCG, /* G: */
14453901Smckusick PART_UNUSED, /* H: */
14553901Smckusick },
14653901Smckusick {
14753901Smckusick 206, /* range_min */
14853901Smckusick 356, /* range_max */
14953901Smckusick
15053901Smckusick 15884, /* A: */
15153901Smckusick 33440, /* B: */
15253901Smckusick PART_SPEC, /* C: */
15353901Smckusick 15884, /* D: */
15453901Smckusick 55936, /* E: */
15553901Smckusick PART_CALCF, /* F: */
15653901Smckusick PART_CALCG, /* G: */
15753901Smckusick 291346, /* H: */
15853901Smckusick },
15953901Smckusick {
16053901Smckusick 356, /* range_min */
16153901Smckusick 99999999, /* range_max */
16253901Smckusick
16353901Smckusick 15884, /* A: */
16453901Smckusick 66880, /* B: */
16553901Smckusick PART_SPEC, /* C: */
16653901Smckusick 15884, /* D: */
16753901Smckusick 307200, /* E: */
16853901Smckusick PART_CALCF, /* F: */
16953901Smckusick PART_CALCG, /* G: */
17053901Smckusick 291346, /* H: */
17153901Smckusick },
17253901Smckusick { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
17353901Smckusick };
17453901Smckusick
17553901Smckusick /************* ADDITIONAL SENSE ERROR CODES *************************/
17653901Smckusick
17753901Smckusick struct msg_list {
17853901Smckusick int ml_code; /* message code */
17953901Smckusick int ml_msglvl; /* message level */
18053901Smckusick char *ml_msgstr; /* message string */
18153901Smckusick };
18253901Smckusick
18353901Smckusick #define sdskeylist skeylist
18453901Smckusick
18553901Smckusick struct msg_list ecodelist_mo[] = {
18653901Smckusick { 0x80, 0, NULL },
18753901Smckusick { 0x81, 0, NULL },
18853901Smckusick { 0x82, 0, NULL },
18953901Smckusick { 0x83, 0, NULL },
19053901Smckusick
19153901Smckusick { -1, 0, NULL }
19253901Smckusick };
19353901Smckusick
19453901Smckusick /************** Ref. sd_var.c ********************************/
19553901Smckusick
19653901Smckusick extern struct iop/**/_ctlr *sdminfo[];
19753901Smckusick extern struct iop/**/_device *sddinfo[];
19853901Smckusick extern struct iop/**/_device *sdip[][MAXSLAVE];
19953901Smckusick
20053901Smckusick extern struct buf rsdbuf[]; /* buffer for raw I/O */
20153901Smckusick extern struct buf csdbuf[]; /* buffer for controll */
20253901Smckusick extern struct buf sdutab[]; /* per drive buffers */
20353901Smckusick
20453901Smckusick extern struct sdc_softc sdc_softc[];
20553901Smckusick extern struct sdd_softc sdd_softc[];
20653901Smckusick extern u_char sd_b_openf[][PNUM];
20753901Smckusick extern u_char sd_c_openf[][PNUM];
20853901Smckusick
20953901Smckusick extern struct scsi kernscsi[];
21053901Smckusick extern struct sdst sdstdrv[];
21153901Smckusick extern struct disklabel sdlabel[];
21253901Smckusick extern struct size sdsizedrv[][PNUM];
21353901Smckusick
21453901Smckusick extern u_char sdc_rsense[][RSEN_CNT];
21553901Smckusick
21653901Smckusick extern struct sync_param sd_sync_param[];
21753901Smckusick
21853901Smckusick extern int nsd;
21953901Smckusick extern int nsdc;
22053901Smckusick
22153901Smckusick /************** Ref. sddefs.c *********************************/
22253901Smckusick
22353901Smckusick extern struct sddevinfo sddevinfo[];
22453901Smckusick
22553901Smckusick /**************************************************************/
22653901Smckusick
22753901Smckusick extern struct msg_list skeylist[];
22853901Smckusick extern struct msg_list ecodelist[];
22953901Smckusick
23053901Smckusick extern int boothowto;
23153901Smckusick extern int rsense_msg_disp; /* RSENSE-message display flag */
23253901Smckusick extern int mo_disp_format; /* MO format mode display flag */
23353901Smckusick
23453901Smckusick int sd_ignore_error;
23553901Smckusick
23653901Smckusick static int re_init_done;
23753901Smckusick
23853901Smckusick static u_char sdwork[2340]; /* buffer for error recovery */
23953901Smckusick static u_char sdtmp[DEV_BSIZE]; /* buffer for temporary */
24053901Smckusick #ifdef mips
24153901Smckusick volatile static int sdtmp_stat = 0; /* status of sdtmp */
24253901Smckusick #else
24353901Smckusick static int sdtmp_stat = 0; /* status of sdtmp */
24453901Smckusick #endif
24553901Smckusick
24653901Smckusick char pname[] = "abcdefgh";
24753901Smckusick
24853901Smckusick struct scsi *get_scsi();
24953901Smckusick struct sc_map *get_sc_map();
25053901Smckusick struct sc_inq *get_sc_inq();
25153901Smckusick
25253901Smckusick int sdprobe(), sdslave(), sdattach(), sddgo(), sdintr();
25353901Smckusick int sdwstart, sdwatch(), sdstop(); /* Have started guardian */
25453901Smckusick void sdexec();
25553901Smckusick
25657173Sutashiro static sd_check(), sd_tstdrv(), sd_other_pages(), sd_err_rcv(), sd_synctr_on();
25757173Sutashiro static disklabel2sdst(), sdst2disklabel(), sd_scu_exec();
25857173Sutashiro
25953901Smckusick #ifdef CPU_SINGLE
26053901Smckusick struct hb_driver sdcdriver =
26153901Smckusick {sdprobe, sdslave, sdattach, sddgo, sdintr, "sd", sddinfo, "sdc", sdminfo};
26253901Smckusick #else
26353901Smckusick struct iop_driver sdcdriver =
26453901Smckusick {sdprobe, sdslave, sdattach, sddgo, "sd", sddinfo, "sdc", sdminfo};
26553901Smckusick #endif
26653901Smckusick
26753901Smckusick /*ARGSUSED*/
26853901Smckusick sdprobe(im)
26953901Smckusick struct iop/**/_ctlr *im;
27053901Smckusick {
27153901Smckusick static int sdd_init = 0;
27253901Smckusick register struct sc_inq *sci;
27353901Smckusick register int ctlr;
27453901Smckusick register int fw;
27553901Smckusick int i;
27653901Smckusick
27753901Smckusick if (sdd_init == 0) {
27853901Smckusick sdd_init++;
27953901Smckusick for (i = 0; i < nsd; i++)
28053901Smckusick sdd_softc[i].sdd_start = -2;
28153901Smckusick }
28253901Smckusick
28353901Smckusick sci = get_sc_inq(im->im_intr);
28453901Smckusick ctlr = im->im_ctlr;
28553901Smckusick /*
28653901Smckusick * Check device type
28753901Smckusick * 0x00: Direct access device.
28853901Smckusick * 0x01: Sequential access device.
28953901Smckusick * 0x04: Write-once read-multiple device.
29053901Smckusick * 0x05: Read-only Direct-access device.
29153901Smckusick * 0x7f: Specified device is nonexistent.
29253901Smckusick */
29353901Smckusick fw = sdc_softc[ctlr].sdc_firmware & ~SDCFW_DEVMASK;
29453901Smckusick
29553901Smckusick switch (sci->sci_devtype) {
29653901Smckusick
29753901Smckusick case 0x00:
29853901Smckusick /*
29953901Smckusick * Assumed that the device is HD.
30053901Smckusick * Later, distinguish MO from HD.
30153901Smckusick */
30253901Smckusick sdc_softc[ctlr].sdc_firmware = fw | SDCFW_HD;
30353901Smckusick break;
30453901Smckusick
30553901Smckusick default:
30653901Smckusick /*
30753901Smckusick * device type mis-match
30853901Smckusick */
30953901Smckusick return (0);
31053901Smckusick }
31153901Smckusick
31253901Smckusick /*
31353901Smckusick * Set interrupt handler routine
31453901Smckusick */
31553901Smckusick if (set_inthandler(im, sdintr) == 0)
31653901Smckusick return (0);
31753901Smckusick
31853901Smckusick return (1);
31953901Smckusick }
32053901Smckusick
32153901Smckusick
32253901Smckusick /*ARGSUSED*/
sdslave(ii,reg,intr)32353901Smckusick sdslave(ii, reg, intr)
32453901Smckusick register struct iop/**/_device *ii;
32553901Smckusick caddr_t reg;
32653901Smckusick int intr;
32753901Smckusick {
32853901Smckusick register struct scsi *sc;
32953901Smckusick
33053901Smckusick sc = get_scsi(intr);
33153901Smckusick sdip[ii->ii_ctlr][ii->ii_slave] = ii;
33253901Smckusick ii->ii_intr = intr;
33353901Smckusick
33453901Smckusick /*
33553901Smckusick * check what the device is.
33653901Smckusick */
33753901Smckusick if ((ii->ii_type = sd_check(ii, sc)) < 0)
33853901Smckusick goto bad_slave;
33953901Smckusick
34053901Smckusick /*
34153901Smckusick * set up ERROR RECOVERY PARAMETERS
34253901Smckusick */
34353901Smckusick if (sd_err_rcv(ii, sc) < 0)
34453901Smckusick goto bad_slave;
34553901Smckusick
34653901Smckusick /*
34753901Smckusick * set up OTHER PARAMETERS
34853901Smckusick */
34953901Smckusick if (sd_other_pages(ii, sc) < 0)
35053901Smckusick goto bad_slave;
35153901Smckusick
35253901Smckusick /*
35353901Smckusick * set up Synchronous Transfer
35453901Smckusick */
35553901Smckusick sd_synctr_on(ii, sc);
35653901Smckusick
35753901Smckusick return (1);
35853901Smckusick
35953901Smckusick bad_slave:
36053901Smckusick /*
36153901Smckusick * no such slave
36253901Smckusick */
36353901Smckusick ii->ii_intr = -1;
36453901Smckusick return (0);
36553901Smckusick }
36653901Smckusick
identity_check(sci,capacity,unit)36753901Smckusick identity_check(sci, capacity, unit)
36853901Smckusick register struct sc_inq *sci;
36953901Smckusick int capacity;
37053901Smckusick int unit;
37153901Smckusick {
37253901Smckusick register struct sddevinfo *sdi;
37353901Smckusick register u_char *id_name;
37453901Smckusick register int index;
37553901Smckusick register int i;
37653901Smckusick int id_pass;
37753901Smckusick
37853901Smckusick id_name = sci->sci_vendid;
37953901Smckusick while (*id_name == ' ')
38053901Smckusick id_name++;
38153901Smckusick
38253901Smckusick index = UNKNOWN_DISK;
38353901Smckusick id_pass = 0;
38453901Smckusick for (sdi = sddevinfo; sdi->id_len >= 0; sdi++) {
38553901Smckusick /*
38653901Smckusick * check vendor & product ID
38753901Smckusick */
38853901Smckusick if (strncmp(id_name, sdi->id_name, sdi->id_len) != 0)
38953901Smckusick continue;
39053901Smckusick id_pass = sdi - sddevinfo;
39153901Smckusick
39253901Smckusick /*
39353901Smckusick * check revision
39453901Smckusick */
39553901Smckusick if (strncmp(sdi->revs, sci->sci_revision, 4) == 0)
39653901Smckusick index = id_pass;
39753901Smckusick else {
39853901Smckusick for (i = 0; i < 4; i++) {
39953901Smckusick if (*(sdi->revs + i) == '?')
40053901Smckusick continue;
40153901Smckusick if (*(sdi->revs + i) != sci->sci_revision[i])
40253901Smckusick break;
40353901Smckusick }
40453901Smckusick if (i < 4)
40553901Smckusick continue;
40653901Smckusick }
40753901Smckusick
40853901Smckusick /*
40953901Smckusick * check capacity
41053901Smckusick */
41153901Smckusick if (capacity == -1)
41253901Smckusick break;
41353901Smckusick if (sdi->capacity == -1) {
41453901Smckusick printf("sd%d: capacity=0x%x(%d)\n",
41553901Smckusick unit, capacity, capacity);
41653901Smckusick break;
41753901Smckusick }
41853901Smckusick if (capacity == sdi->capacity)
41953901Smckusick break;
42053901Smckusick }
42153901Smckusick if (index == 0)
42253901Smckusick index = id_pass;
42353901Smckusick
42453901Smckusick return (index);
42553901Smckusick }
42653901Smckusick
search_index(type)42753901Smckusick search_index(type)
42853901Smckusick register int type;
42953901Smckusick {
43053901Smckusick register struct sddevinfo *sdi;
43153901Smckusick register int i;
43253901Smckusick int index;
43353901Smckusick
43453901Smckusick index = UNKNOWN_DISK;
43553901Smckusick i = 0;
43653901Smckusick for (sdi = sddevinfo; sdi->id_len > 0; sdi++) {
43753901Smckusick if (sdi->type == type) {
43853901Smckusick index = i;
43953901Smckusick break;
44053901Smckusick }
44153901Smckusick i++;
44253901Smckusick }
44353901Smckusick return (index);
44453901Smckusick }
44553901Smckusick
44653901Smckusick static
sd_check(ii,sc)44753901Smckusick sd_check(ii, sc)
44853901Smckusick register struct iop/**/_device *ii;
44953901Smckusick register struct scsi *sc;
45053901Smckusick {
45153901Smckusick register struct sc_inq *sci;
45253901Smckusick register struct sc_rcap *scr;
45353901Smckusick register int intr;
45453901Smckusick register int slave;
45553901Smckusick register int unit;
45653901Smckusick struct sdc_softc *sdc;
45753901Smckusick struct sdd_softc *sdd;
45853901Smckusick struct sc_extnd *sce;
45953901Smckusick int retrycnt;
46053901Smckusick int index;
46153901Smckusick int media_in;
46253901Smckusick
46353901Smckusick intr = ii->ii_intr;
46453901Smckusick slave = ii->ii_slave;
46553901Smckusick unit = ii->ii_unit;
46653901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
46753901Smckusick sdd = &sdd_softc[unit];
46853901Smckusick scr = (struct sc_rcap *)sc->sc_param;
46953901Smckusick sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
47053901Smckusick
47153901Smckusick /*
47253901Smckusick * check if the logical unit is ready.
47353901Smckusick * (by TEST UNIT READY command)
47453901Smckusick */
47553901Smckusick media_in = sd_tstdrv(ii, sc);
47653901Smckusick if (media_in < 0)
47753901Smckusick return (-3);
47853901Smckusick
47953901Smckusick /*
48053901Smckusick * Get controller and drive information.
48153901Smckusick * (by INQUIRY command)
48253901Smckusick */
48353901Smckusick retrycnt = 0;
48453901Smckusick sci = get_sc_inq(intr);
48553901Smckusick loop_inq:
48653901Smckusick if (retrycnt++ > MAXPROBERETRY)
48753901Smckusick return (-1);
48853901Smckusick
48953901Smckusick scop_inquiry(intr, sc, slave, SCSI_INTDIS, sizeof(struct sc_inq), sci);
49053901Smckusick sc->sc_tstatus &= TGSTMASK;
49153901Smckusick
49253901Smckusick if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD) {
49353901Smckusick
49453901Smckusick bzero((caddr_t)sce, RSEN_CNT);
49553901Smckusick scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
49653901Smckusick (caddr_t)sce);
49753901Smckusick sc->sc_tstatus &= TGSTMASK;
49853901Smckusick if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD)
49953901Smckusick return (-1);
50053901Smckusick if (sce->sce_extend != 0x70)
50153901Smckusick goto loop_inq;
50253901Smckusick
50353901Smckusick switch (sce->sce_sdecode) {
50453901Smckusick
50553901Smckusick case 0x04: /* Drive Not Ready */
50653901Smckusick case 0x28: /* Medium Changed */
50753901Smckusick case 0x29: /* Power On or Reset or Bus Device Reset */
50853901Smckusick case 0x2a: /* Mode Select Parameter Changed */
50953901Smckusick break;
51053901Smckusick
51153901Smckusick default:
51253901Smckusick return (-1);
51353901Smckusick }
51453901Smckusick DELAY(D100MSEC); /* wait 100 ms. */
51553901Smckusick goto loop_inq;
51653901Smckusick }
51753901Smckusick
51853901Smckusick index = identity_check(sci, -1, unit);
51953901Smckusick
52053901Smckusick switch (sddevinfo[index].type) {
52153901Smckusick
52253901Smckusick case SMO_S501:
52353901Smckusick case SMO_S501_ISO:
52453901Smckusick case SMO_S501_ISO2:
52553901Smckusick sdc->sdc_firmware =
52653901Smckusick SDCFW_MO | (sdc->sdc_firmware & ~SDCFW_DEVMASK);
52753901Smckusick break;
52853901Smckusick
52953901Smckusick defaults:
53053901Smckusick break;
53153901Smckusick }
53253901Smckusick
53353901Smckusick if (sci->sci_qual & 0x80) {
53453901Smckusick /*
53553901Smckusick * removable medium device
53653901Smckusick */
53753901Smckusick sdc->sdc_firmware |= SDCFW_RMB;
53853901Smckusick if ((media_in == 0) || ((sdc->sdc_firmware & SDCFW_MO) == 0))
53953901Smckusick return (index);
54053901Smckusick }
54153901Smckusick
54253901Smckusick /****************/
54353901Smckusick /* HD & MO only */
54453901Smckusick /****************/
54553901Smckusick /*
54653901Smckusick * Get drive capacity
54753901Smckusick * (by READ CAPACITY command)
54853901Smckusick */
54953901Smckusick retrycnt = 0;
55053901Smckusick loop_rcap:
55153901Smckusick if (retrycnt++ > MAXPROBERETRY)
55253901Smckusick return (-4);
55353901Smckusick
55453901Smckusick scop_rcap(intr, sc, slave, SCSI_INTDIS, 8, (caddr_t)0);
55553901Smckusick sc->sc_tstatus &= TGSTMASK;
55653901Smckusick if (sc->sc_istatus != INST_EP)
55753901Smckusick return (-5);
55853901Smckusick if (sc->sc_tstatus == TGST_CC) {
55953901Smckusick bzero((caddr_t)sce, RSEN_CNT);
56053901Smckusick scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
56153901Smckusick (caddr_t)sce);
56253901Smckusick sc->sc_tstatus &= TGSTMASK;
56353901Smckusick if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD)
56453901Smckusick return (-6);
56553901Smckusick if (sderrordisp((caddr_t)sce, ii) == FORMAT_MODE_CORRUPTED) {
56653901Smckusick scr->scr_nblock = 0;
56753901Smckusick scr->scr_blocklen = DEV_BSIZE;
56853901Smckusick sdd->sdd_flags |= SDDF_NONFMT;
56953901Smckusick } else {
57053901Smckusick DELAY(D100MSEC); /* wait 100 ms. */
57153901Smckusick goto loop_rcap;
57253901Smckusick }
57353901Smckusick }
57453901Smckusick else if (sc->sc_tstatus != TGST_GOOD) {
57553901Smckusick DELAY(D100MSEC); /* wait 100 ms. */
57653901Smckusick goto loop_rcap;
57753901Smckusick }
57853901Smckusick
57953901Smckusick sdd->sdd_nsect = scr->scr_nblock + 1;
58053901Smckusick sdd->sdd_sectsize = scr->scr_blocklen;
58153901Smckusick
58253901Smckusick index = identity_check(sci, scr->scr_nblock +1, unit);
58353901Smckusick
58453901Smckusick return (index);
58553901Smckusick }
58653901Smckusick
58753901Smckusick static
sd_tstdrv(ii,sc)58853901Smckusick sd_tstdrv(ii, sc)
58953901Smckusick register struct iop/**/_device *ii;
59053901Smckusick register struct scsi *sc;
59153901Smckusick {
59253901Smckusick register struct sc_extnd *sce;
59353901Smckusick register int intr;
59453901Smckusick register int slave;
59553901Smckusick register int retrycnt;
59653901Smckusick struct sdc_softc *sdc;
59753901Smckusick struct sdd_softc *sdd;
59853901Smckusick
59953901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
60053901Smckusick sdd = &sdd_softc[ii->ii_unit];
60153901Smckusick
60253901Smckusick intr = ii->ii_intr;
60353901Smckusick slave = ii->ii_slave;
60453901Smckusick sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
60553901Smckusick retrycnt = 0;
60653901Smckusick loop_tst:
60753901Smckusick if (retrycnt++ > MAXPROBERETRY)
60853901Smckusick return (-1);
60953901Smckusick
61053901Smckusick scop_tst(intr, sc, slave, SCSI_INTDIS);
61153901Smckusick sc->sc_tstatus &= TGSTMASK;
61253901Smckusick if (sc->sc_istatus != INST_EP) {
61353901Smckusick DELAY(D100MSEC); /* wait 100 ms. */
61453901Smckusick goto loop_tst;
61553901Smckusick }
61653901Smckusick
61753901Smckusick switch (sc->sc_tstatus) {
61853901Smckusick
61953901Smckusick case TGST_CC:
62053901Smckusick /* Get error code */
62153901Smckusick bzero((caddr_t)sce, RSEN_CNT);
62253901Smckusick scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
62353901Smckusick (caddr_t)sce);
62453901Smckusick sc->sc_tstatus &= TGSTMASK;
62553901Smckusick if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD) {
62653901Smckusick DELAY(D100MSEC); /* wait 100 ms. */
62753901Smckusick goto loop_tst;
62853901Smckusick }
62953901Smckusick
63053901Smckusick if (sce->sce_extend != 0x70)
63153901Smckusick goto loop_tst;
63253901Smckusick
63353901Smckusick switch (sce->sce_skey) {
63453901Smckusick
63553901Smckusick case 0x0: /* No Sense */
63653901Smckusick case 0x4: /* Hardware error */
63753901Smckusick case 0x6: /* Unit attention */
63853901Smckusick goto loop_tst;
63953901Smckusick
64053901Smckusick case 0x2: /* Not ready */
64153901Smckusick switch (sce->sce_sdecode) {
64253901Smckusick
64353901Smckusick case 0x04: /* Not ready */
64453901Smckusick /*
64553901Smckusick * Drive not ready... so start..
64653901Smckusick */
64753901Smckusick scop_stst(intr, sc, slave, SCSI_INTDIS, SDSS_START);
64853901Smckusick DELAY(D100MSEC * 10); /* wait 1 sec. */
64953901Smckusick goto loop_tst;
65053901Smckusick
65153901Smckusick case 0x0a: /* No Disk *//*MO*/
65253901Smckusick default:
65353901Smckusick DELAY(D100MSEC);
65453901Smckusick goto loop_tst;
65553901Smckusick }
65653901Smckusick break;
65753901Smckusick
65853901Smckusick case 0x03:
65953901Smckusick if (sce->sce_sdecode == FORMAT_MODE_CORRUPTED)
66053901Smckusick return (1); /* ignore error */
66153901Smckusick /* fall through */
66253901Smckusick
66353901Smckusick default:
66453901Smckusick return (-2);
66553901Smckusick }
66653901Smckusick break;
66753901Smckusick
66853901Smckusick case TGST_BUSY:
66953901Smckusick goto loop_tst;
67053901Smckusick
67153901Smckusick case TGST_GOOD:
67253901Smckusick break;
67353901Smckusick
67453901Smckusick default:
67553901Smckusick return (-3);
67653901Smckusick }
67753901Smckusick
67853901Smckusick return (1);
67953901Smckusick }
68053901Smckusick
68153901Smckusick static
sd_other_pages(ii,sc)68253901Smckusick sd_other_pages(ii, sc)
68353901Smckusick register struct iop/**/_device *ii;
68453901Smckusick register struct scsi *sc;
68553901Smckusick {
68653901Smckusick register struct sddevinfo *sdi;
68753901Smckusick char **p;
68853901Smckusick char *page;
68953901Smckusick int length;
69053901Smckusick int retrycnt;
69153901Smckusick int len;
69253901Smckusick
69353901Smckusick sdi = &sddevinfo[ii->ii_type];
69453901Smckusick if ((p = sdi->other_pages) == NULL)
69553901Smckusick return (0);
69653901Smckusick
69753901Smckusick /*
69853901Smckusick * set other parameters
69953901Smckusick */
70053901Smckusick while (page = *p++) {
70153901Smckusick retrycnt = 0;
70253901Smckusick loop_other_pages:
70353901Smckusick bzero((caddr_t)sdtmp, 4);
70453901Smckusick length = *(page + 1) + 2;
70553901Smckusick bcopy(page, &sdtmp[4], length);
70653901Smckusick if (retrycnt++ > MAXPROBERETRY)
70753901Smckusick return (-1);
70853901Smckusick
70953901Smckusick scop_mselect(ii->ii_intr, sc, ii->ii_slave, SCSI_INTDIS,
71053901Smckusick (SDM_PF<<24) + length +4, (caddr_t)sdtmp);
71153901Smckusick sc->sc_tstatus &= TGSTMASK;
71253901Smckusick if ((sc->sc_istatus != INST_EP)
71353901Smckusick || (sc->sc_tstatus != TGST_GOOD)) {
71453901Smckusick struct sc_extnd *sce;
71553901Smckusick
71653901Smckusick sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
71753901Smckusick scop_rsense(ii->ii_intr, sc, ii->ii_slave, SCSI_INTDIS,
71853901Smckusick RSEN_CNT, (caddr_t)sce);
71953901Smckusick switch (sce->sce_skey) {
72053901Smckusick
72153901Smckusick case 0x00:
72253901Smckusick case 0x02:
72353901Smckusick case 0x04:
72453901Smckusick case 0x06:
72553901Smckusick DELAY(D100MSEC); /* 100 ms. */
72653901Smckusick goto loop_other_pages;
72753901Smckusick
72853901Smckusick default:
72953901Smckusick return (-1);
73053901Smckusick }
73153901Smckusick }
73253901Smckusick }
73353901Smckusick
73453901Smckusick if (sdi->firm_flags & FIRM_CACHE_ON)
73553901Smckusick sdc_softc[ii->ii_ctlr].sdc_firmware |= SDCFW_CACHE;
73653901Smckusick else
73753901Smckusick sdc_softc[ii->ii_ctlr].sdc_firmware &= ~SDCFW_CACHE;
73853901Smckusick
73953901Smckusick return (1);
74053901Smckusick }
74153901Smckusick
74253901Smckusick static
sd_err_rcv(ii,sc)74353901Smckusick sd_err_rcv(ii, sc)
74453901Smckusick register struct iop/**/_device *ii;
74553901Smckusick register struct scsi *sc;
74653901Smckusick {
74753901Smckusick register struct sdc_softc *sdc;
74853901Smckusick register int intr;
74953901Smckusick register int slave;
75053901Smckusick register int len;
75153901Smckusick struct sc_extnd *sce;
75253901Smckusick struct sdd_softc *sdd;
75353901Smckusick struct sddevinfo *sdi;
75453901Smckusick int retrycnt;
75553901Smckusick char *erp_page;
75653901Smckusick
75753901Smckusick intr = ii->ii_intr;
75853901Smckusick slave = ii->ii_slave;
75953901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
76053901Smckusick sdd = &sdd_softc[ii->ii_unit];
76153901Smckusick sdi = &sddevinfo[ii->ii_type];
76253901Smckusick sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
76353901Smckusick
76453901Smckusick /*
76553901Smckusick * set Default DISK sector size
76653901Smckusick */
76753901Smckusick if (sdd->sdd_sectsize == 0)
76853901Smckusick sdd->sdd_sectsize = DEV_BSIZE;
76953901Smckusick
77053901Smckusick
77153901Smckusick if (sdi->ERP_page == NULL) {
77253901Smckusick /*
77353901Smckusick * use default error recovery parameters
77453901Smckusick */
77553901Smckusick sdc->sdc_firmware |= SDCFW_DEFMODE;
77653901Smckusick return (0);
77753901Smckusick }
77853901Smckusick
77953901Smckusick if (sdi->firm_flags & FIRM_AWRE)
78053901Smckusick sdc->sdc_firmware |= SDCFW_AWRE;
78153901Smckusick if (sdi->firm_flags & FIRM_ARRE)
78253901Smckusick sdc->sdc_firmware |= SDCFW_ARRE;
78353901Smckusick /*
78453901Smckusick * set ERROR RECOVERY PARAMETERS
78553901Smckusick */
78653901Smckusick loop_err_rcv:
78753901Smckusick bzero((caddr_t)sdtmp, 4);
78853901Smckusick erp_page = sdi->ERP_page;
78953901Smckusick len = *(erp_page + 1) + 2;
79053901Smckusick bcopy(erp_page, &sdtmp[4], len);
79153901Smckusick
79253901Smckusick scop_mselect(intr, sc, slave, SCSI_INTDIS,
79353901Smckusick (SDM_PF<<24) + len +4, (caddr_t)sdtmp);
79453901Smckusick sc->sc_tstatus &= TGSTMASK;
79553901Smckusick if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD) {
79653901Smckusick if (sc->sc_tstatus == TGST_CC) {
79753901Smckusick bzero((caddr_t)sce, RSEN_CNT);
79853901Smckusick scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
79953901Smckusick (caddr_t)sce);
80053901Smckusick if (sce->sce_sdecode == 0x2a) {
80153901Smckusick /* mode select parameter changed */
80253901Smckusick goto ercv_done;
80353901Smckusick } else if (sce->sce_skey == 0x6) {
80453901Smckusick /* unit attention */
80553901Smckusick goto loop_err_rcv;
80653901Smckusick }
80753901Smckusick }
80853901Smckusick /*
80953901Smckusick * use default ERROR RECOVERY mode
81053901Smckusick */
81153901Smckusick sdc->sdc_firmware |= SDCFW_DEFMODE;
81253901Smckusick sdc->sdc_firmware &= ~(SDCFW_AWRE|SDCFW_ARRE);
81353901Smckusick }
81453901Smckusick
81553901Smckusick ercv_done:
81653901Smckusick
81753901Smckusick return (1);
81853901Smckusick }
81953901Smckusick
82053901Smckusick static
sd_synctr_on(ii,sc)82153901Smckusick sd_synctr_on(ii, sc)
82253901Smckusick register struct iop/**/_device *ii;
82353901Smckusick register struct scsi *sc;
82453901Smckusick {
82553901Smckusick register struct sddevinfo *sdi;
82653901Smckusick register struct sync_param *syncp;
82753901Smckusick
82853901Smckusick sdi = &sddevinfo[ii->ii_type];
82953901Smckusick
83053901Smckusick if (sdi->firm_flags & FIRM_SYNCTR) {
83153901Smckusick scinit(sc, ii->ii_slave, DEV_BSIZE);
83253901Smckusick sc->sc_opcode = SCOP_TST;
83353901Smckusick sc->sc_message = MSG_EXTND; /* extended message */
83453901Smckusick sc->sc_param[0] = MSG_EXTND;
83553901Smckusick sc->sc_param[1] = 0x03;
83653901Smckusick sc->sc_param[2] = 0x01; /* synchronous transfer */
83753901Smckusick sc->sc_param[3] = sdi->tr_period; /* transfer period */
83853901Smckusick sc->sc_param[4] = sdi->tr_offset; /* REQ offset */
83953901Smckusick
84053901Smckusick if (sdc_softc[ii->ii_ctlr].sdc_firmware & SDCFW_CACHE)
84153901Smckusick sc->sc_tstatus |= TS_CONTR_ON; /* contiguous TR ON */
84253901Smckusick else
84353901Smckusick sc->sc_tstatus |= TS_CONTR_OFF; /* contiguous TR OFF */
84453901Smckusick
84553901Smckusick #ifdef news1800
84653901Smckusick if (scsi_berr_bug() != 0) {
84753901Smckusick sc->sc_tstatus &= ~TS_CONTR_ON;
84853901Smckusick sc->sc_tstatus |= TS_CONTR_OFF;
84953901Smckusick }
85053901Smckusick #endif
85153901Smckusick
85253901Smckusick if (sc->sc_tstatus & TS_CONTR_OFF)
85353901Smckusick sdc_softc[ii->ii_ctlr].sdc_firmware &= ~SDCFW_CONTR;
85453901Smckusick else
85553901Smckusick sdc_softc[ii->ii_ctlr].sdc_firmware |= SDCFW_CONTR;
85653901Smckusick
85753901Smckusick sc_go(ii->ii_intr, sc, SCSI_INTDIS);
85853901Smckusick
85953901Smckusick syncp = &sd_sync_param[ii->ii_unit];
86053901Smckusick syncp->tr_period = sc->sc_param[3];
86153901Smckusick syncp->tr_offset = sc->sc_param[4];
86253901Smckusick if (sc->sc_param[4])
86353901Smckusick sdd_softc[ii->ii_unit].sdd_flags |= SDDF_SYNCTR;
86453901Smckusick }
86553901Smckusick }
86653901Smckusick
86753901Smckusick
sdattach(ii)86853901Smckusick sdattach(ii)
86953901Smckusick register struct iop/**/_device *ii;
87053901Smckusick {
87153901Smckusick register int unit;
87253901Smckusick register int i;
87353901Smckusick struct sdc_softc *sdc;
87453901Smckusick struct sdd_softc *sdd;
87553901Smckusick int dummy;
87653901Smckusick
87753901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
87853901Smckusick sdc->sdc_timeo = 60; /* timeout 60 sec */
87953901Smckusick
88053901Smckusick unit = ii->ii_unit;
88153901Smckusick sdd = &sdd_softc[unit];
88253901Smckusick sdd->sdd_stoptime = OD_STOPTIME; /* REMOVABLE MEDIA */
88353901Smckusick sdd->sdd_start = -2;
88453901Smckusick
88553901Smckusick sdmaptype(ii);
88653901Smckusick
88753901Smckusick if (sdwstart == 0) {
88853901Smckusick sdwstart++;
88953901Smckusick timeout(sdwatch, (caddr_t)0, hz);
89053901Smckusick timeout(sdstop, (caddr_t)0, hz);
89153901Smckusick }
89253901Smckusick
89353901Smckusick /*
89453901Smckusick * initialize open flag
89553901Smckusick */
89653901Smckusick for (i = 0; i < PNUM; i++) {
89753901Smckusick sd_b_openf[unit][i] = 0;
89853901Smckusick sd_c_openf[unit][i] = 0;
89953901Smckusick }
90053901Smckusick
90153901Smckusick if (re_init_done > 0)
90253901Smckusick return;
90353901Smckusick
90453901Smckusick if (sdc->sdc_firmware & SDCFW_HD) {
90553901Smckusick /*
90653901Smckusick * If device is Hard Disk,
90753901Smckusick * then get partition information.
90853901Smckusick */
90953901Smckusick sdrpartinfo(ii);
91053901Smckusick dummy = DEV_BSIZE * sdstdrv[unit].rps * sdstdrv[unit].nsect;
91153901Smckusick } else
91253901Smckusick dummy = DEV_BSIZE * 40 * 31;
91353901Smckusick
91453901Smckusick if (ii->ii_dk >= 0 && dummy)
91553901Smckusick dk_wpms[ii->ii_dk] = dummy / (2 * 1000000);
91653901Smckusick }
91753901Smckusick
sdmaptype(ii)91853901Smckusick sdmaptype(ii)
91953901Smckusick register struct iop/**/_device *ii;
92053901Smckusick {
92153901Smckusick printf("sd%d: %s\n", ii->ii_unit, sddevinfo[ii->ii_type].call_name);
92253901Smckusick }
92353901Smckusick
92453901Smckusick int sd_b_major = -1;
92553901Smckusick
sd_b_open(dev,flag)92653901Smckusick sd_b_open(dev, flag)
92753901Smckusick dev_t dev;
92853901Smckusick int flag;
92953901Smckusick {
93053901Smckusick sd_b_major = major(dev);
93153901Smckusick return (_sdopen(dev, flag, S_IFBLK));
93253901Smckusick }
93353901Smckusick
93453901Smckusick int sd_c_major = -1;
93553901Smckusick
sd_c_open(dev,flag)93653901Smckusick sd_c_open(dev, flag)
93753901Smckusick dev_t dev;
93853901Smckusick int flag;
93953901Smckusick {
94053901Smckusick sd_c_major = major(dev);
94153901Smckusick return (_sdopen(dev, flag, S_IFCHR));
94253901Smckusick }
94353901Smckusick
_sdopen(dev,flag,fmt)94453901Smckusick _sdopen(dev, flag, fmt)
94553901Smckusick register dev_t dev;
94653901Smckusick int flag;
94753901Smckusick int fmt;
94853901Smckusick {
94953901Smckusick register struct iop/**/_device *ii;
95053901Smckusick register struct sdd_softc *sdd;
95153901Smckusick register struct sdc_softc *sdc;
95253901Smckusick register struct sddevinfo *sdi;
95353901Smckusick register int unit;
95453901Smckusick register int i;
95553901Smckusick u_char *sdopfp;
95653901Smckusick u_char old_sdopf;
95753901Smckusick int media_changed;
95853901Smckusick int s;
95953901Smckusick int stat;
96053901Smckusick struct scsi uscsi;
96153901Smckusick
96253901Smckusick unit = dev2unit(dev);
96353901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
96453901Smckusick return (ENXIO);
96553901Smckusick
96653901Smckusick sdd = &sdd_softc[unit];
96753901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
96853901Smckusick sdi = &sddevinfo[ii->ii_type];
96953901Smckusick
97053901Smckusick if (sdd->sdd_flags & SDDF_XUSE)
97153901Smckusick return (EBUSY);
97253901Smckusick
97353901Smckusick /*
97453901Smckusick * LOCK while sdstop() running.
97553901Smckusick */
97653901Smckusick s = splclock();
97753901Smckusick while (sdc->sdc_state & SDCS_SCUNLOCK) {
97853901Smckusick sdc->sdc_state |= SDCS_OPEN_WAIT;
97953901Smckusick sleep((caddr_t)sdc, PRIBIO);
98053901Smckusick }
98153901Smckusick splx(s);
98253901Smckusick
98353901Smckusick /*
98453901Smckusick * LOCK sdtmp buffer
98553901Smckusick */
98653901Smckusick s = splclock();
98753901Smckusick while (sdtmp_stat & B_BUSY) {
98853901Smckusick sdtmp_stat |= B_WANTED;
98953901Smckusick sleep((caddr_t)sdtmp, PRIBIO);
99053901Smckusick }
99153901Smckusick sdtmp_stat |= B_BUSY;
99253901Smckusick splx(s);
99353901Smckusick sdd->sdd_flags |= SDDF_GETTMP;
99453901Smckusick
99553901Smckusick if ((fmt & S_IFMT) == S_IFBLK)
99653901Smckusick sdopfp = &sd_b_openf[unit][dev2part(dev)];
99753901Smckusick else
99853901Smckusick sdopfp = &sd_c_openf[unit][dev2part(dev)];
99953901Smckusick old_sdopf = *sdopfp;
100053901Smckusick if (old_sdopf <= 1)
100153901Smckusick *sdopfp += 1; /* 1: 1st open (ONLY_ONE) */
100253901Smckusick /* 2: already opened */
100353901Smckusick stat = 0;
100453901Smckusick media_changed = 0;
100553901Smckusick
100653901Smckusick /*
100753901Smckusick * From here on until pre_open_done is only for removable devices
100853901Smckusick */
100953901Smckusick if ((sdc->sdc_firmware & SDCFW_RMB) == 0)
101053901Smckusick goto pre_open_done;
101153901Smckusick
101253901Smckusick if ((minor(dev) & 0x80) || (dev == rootdev))
101353901Smckusick sdd->sdd_stoptime = 0x7fffffff; /*XXX*/
101453901Smckusick
101553901Smckusick /*
101653901Smckusick * Start Unit
101753901Smckusick */
101853901Smckusick s = splclock(); /* inhibit clock interrupt */
101953901Smckusick i = sdd->sdd_start;
102053901Smckusick sdd->sdd_start = sdd->sdd_stoptime;
102153901Smckusick splx(s);
102253901Smckusick if (i <= 0) {
102353901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
102453901Smckusick uscsi.sc_opcode = SCOP_STST;
102553901Smckusick uscsi.sc_count = SDSS_START;
102653901Smckusick
102753901Smckusick if (sdcmd(dev, &uscsi)) {
102853901Smckusick sdd->sdd_start = i;
102953901Smckusick if ((flag & FWRITE) == 0)
103053901Smckusick goto sdopen_setup;
103153901Smckusick stat = EIO;
103253901Smckusick goto pre_open_done;
103353901Smckusick }
103453901Smckusick }
103553901Smckusick
103653901Smckusick /*
103753901Smckusick * prevent medium removal
103853901Smckusick */
103953901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
104053901Smckusick uscsi.sc_opcode = SCOP_MEDRMV;
104153901Smckusick uscsi.sc_count = SDRMV_PREV;
104253901Smckusick if (sdcmd(dev, &uscsi)) {
104353901Smckusick stat = EIO;
104453901Smckusick goto pre_open_done;
104553901Smckusick }
104653901Smckusick sdd->sdd_flags |= SDDF_INHRMV;
104753901Smckusick
104853901Smckusick sdopen_setup:
104953901Smckusick if ((sdd->sdd_flags & SDDF_SAMEDSK) == SDDF_DSKCHGD) {
105053901Smckusick sdd->sdd_flags |= SDDF_SAMEDSK;
105153901Smckusick media_changed = 1;
105253901Smckusick
105353901Smckusick /*
105453901Smckusick * From here on until mo_check_done is only for MO device
105553901Smckusick */
105653901Smckusick if ((sdc->sdc_firmware & SDCFW_MO) == 0)
105753901Smckusick goto mo_check_done;
105853901Smckusick
105953901Smckusick /*
106053901Smckusick * Mode Sense
106153901Smckusick */
106253901Smckusick bzero(sdtmp, 36);
106353901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
106453901Smckusick uscsi.sc_cpoint = sdtmp;
106553901Smckusick uscsi.sc_ctrnscnt = 36;
106653901Smckusick uscsi.sc_opcode = SCOP_MSENSE;
106753901Smckusick uscsi.sc_lad = (SDM_PF << 16)|((SDM_PC_CUR|SDM_PCODE_ALL) << 8);
106853901Smckusick uscsi.sc_count = 36;
106953901Smckusick
107053901Smckusick if (sdcmd(dev, &uscsi) == 0) {
107153901Smckusick /*
107253901Smckusick * check Write Protect mode
107353901Smckusick */
107453901Smckusick if (sdtmp[2] & 0x80)
107553901Smckusick sdd->sdd_flags |= SDDF_WPROTECT;
107653901Smckusick else
107753901Smckusick sdd->sdd_flags &= ~SDDF_WPROTECT;
107853901Smckusick /*
107953901Smckusick * check Format Mode
108053901Smckusick */
108153901Smckusick if (sdtmp[26] == 2) {
108253901Smckusick ii->ii_type = search_index(SMO_S501);
108353901Smckusick if (mo_disp_format)
108453901Smckusick printf("sd%d: format mode 2 (original format)\n", unit);
108553901Smckusick } else if (sdtmp[26] == 3) {
108653901Smckusick int spare;
108753901Smckusick
108853901Smckusick spare = *(short *)&sdtmp[32];
108953901Smckusick if (spare == 2048)
109053901Smckusick ii->ii_type =
109153901Smckusick search_index(SMO_S501_ISO2);
109253901Smckusick else
109353901Smckusick ii->ii_type =
109453901Smckusick search_index(SMO_S501_ISO);
109553901Smckusick if (mo_disp_format)
109653901Smckusick printf("sd%d: format mode 3 (ISO format) spare=%d\n", unit, spare);
109753901Smckusick } else {
109853901Smckusick sdd->sdd_flags |= SDDF_NONFMT;
109953901Smckusick if (mo_disp_format)
110053901Smckusick printf("sd%d: Non format\n", unit);
110153901Smckusick }
110253901Smckusick sdi = &sddevinfo[ii->ii_type];
110353901Smckusick }
110453901Smckusick
110553901Smckusick /*
110653901Smckusick * Mode Select
110753901Smckusick * Error Recovery Parameters set
110853901Smckusick */
110953901Smckusick i = *(sdi->ERP_page +1) + 2; /* page length */
111053901Smckusick bzero(sdtmp, i + 4);
111153901Smckusick bcopy(sdi->ERP_page, (caddr_t)&sdtmp[4], i);
111253901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
111353901Smckusick uscsi.sc_cpoint = sdtmp;
111453901Smckusick uscsi.sc_ctrnscnt = i + 4;
111553901Smckusick uscsi.sc_opcode = SCOP_MSELECT;
111653901Smckusick uscsi.sc_lad = (SDM_PF << 16);
111753901Smckusick uscsi.sc_count = i + 4;
111853901Smckusick
111953901Smckusick (void) sdcmd(dev, &uscsi);
112053901Smckusick
112153901Smckusick /*
112253901Smckusick * Read Grown Defect list
112353901Smckusick */
112453901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
112553901Smckusick uscsi.sc_cpoint = sdtmp;
112653901Smckusick uscsi.sc_ctrnscnt = 4;
112753901Smckusick uscsi.sc_opcode = SCOP_RDL;
112853901Smckusick uscsi.sc_cdb.un_type1.t1_ladhi = (SDDL_GLIST|SDDL_PHYSFMT) << 8;
112953901Smckusick uscsi.sc_cdb.un_type1.t1_p3 = 4;
113053901Smckusick
113153901Smckusick (void) sdcmd(dev, &uscsi);
113253901Smckusick i = *(short *)&sdtmp[2] / 8;
113353901Smckusick if (i > (1024*9/10))
113453901Smckusick printf("sd%d: WARNING: DEFECT SPARE LOCATION < 10%\n",
113553901Smckusick unit);
113653901Smckusick mo_check_done:
113753901Smckusick /*
113853901Smckusick * Read Capacity
113953901Smckusick */
114053901Smckusick bzero((caddr_t)sdtmp, 8);
114153901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
114253901Smckusick uscsi.sc_cpoint = sdtmp;
114353901Smckusick uscsi.sc_ctrnscnt = 8;
114453901Smckusick uscsi.sc_opcode = SCOP_RCAP;
114553901Smckusick
114653901Smckusick (void) sdcmd(dev, &uscsi);
114753901Smckusick sdd->sdd_nsect = *(int *)&sdtmp[0] + 1;
114853901Smckusick sdd->sdd_sectsize = *(int *)&sdtmp[4];
114953901Smckusick
115053901Smckusick if ((sdd->sdd_sectsize != DEV_BSIZE)
115153901Smckusick && (sdd->sdd_sectsize != SDBSIZE1K))
115253901Smckusick sdd->sdd_sectsize = DEV_BSIZE;
115353901Smckusick }
115453901Smckusick
115553901Smckusick if ((sdd->sdd_flags & SDDF_WPROTECT) && (flag & FWRITE))
115653901Smckusick stat = EROFS;
115753901Smckusick
115853901Smckusick pre_open_done:
115953901Smckusick
116053901Smckusick if (stat == 0) {
116153901Smckusick if ((isalone(unit) == ONLY_ONE) || media_changed) {
116253901Smckusick /*
116353901Smckusick * read partition information from sector zero.
116453901Smckusick */
116553901Smckusick sdrpartinfo(ii);
116653901Smckusick if (ii->ii_dk >= 0) {
116753901Smckusick dk_wpms[ii->ii_dk] =
116853901Smckusick sdd->sdd_sectsize * sdstdrv[unit].rps
116953901Smckusick * sdstdrv[unit].nsect / (2 * 1000000);
117053901Smckusick }
117153901Smckusick }
117253901Smckusick } else {
117353901Smckusick /*
117453901Smckusick * open error
117553901Smckusick */
117653901Smckusick *sdopfp = old_sdopf;
117753901Smckusick if ((sdd->sdd_flags & SDDF_INHRMV) && (isalone(unit) == 0)) {
117853901Smckusick sdd->sdd_flags &= ~SDDF_INHRMV;
117953901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
118053901Smckusick uscsi.sc_opcode = SCOP_MEDRMV;
118153901Smckusick uscsi.sc_count = SDRMV_ALLOW;
118253901Smckusick (void) sdcmd(dev, &uscsi);
118353901Smckusick }
118453901Smckusick }
118553901Smckusick
118653901Smckusick /*
118753901Smckusick * UNLOCK open
118853901Smckusick */
118953901Smckusick s = splclock();
119053901Smckusick sdd->sdd_flags &= ~SDDF_GETTMP;
119153901Smckusick if (sdtmp_stat & B_WANTED)
119253901Smckusick wakeup((caddr_t)sdtmp);
119353901Smckusick sdtmp_stat &= ~(B_BUSY|B_WANTED);
119453901Smckusick splx(s);
119553901Smckusick return (stat);
119653901Smckusick }
119753901Smckusick
119853901Smckusick int sd_access_check_on; /* Common flags for sd_access_check() */
119953901Smckusick
sd_access_check(bp)120053901Smckusick sd_access_check(bp)
120153901Smckusick register struct buf *bp;
120253901Smckusick {
120353901Smckusick register struct iop/**/_device *ii;
120453901Smckusick register struct sdd_softc *sdd;
120553901Smckusick int unit;
120653901Smckusick int check_part;
120753901Smckusick int limit;
120853901Smckusick int over;
120953901Smckusick register struct size *sizes;
121053901Smckusick register int lba; /* logical block address */
121153901Smckusick register int sz;
121253901Smckusick register int i;
121353901Smckusick
121453901Smckusick check_part = 0;
121553901Smckusick unit = dev2unit(bp->b_dev);
121653901Smckusick ii = sddinfo[unit];
121753901Smckusick sdd = &sdd_softc[unit];
121853901Smckusick sizes = sdstdrv[unit].sizes;
121953901Smckusick
122053901Smckusick lba = sizes[dev2part(bp->b_dev)].sd_blkoff + dkblock(bp);
122153901Smckusick sz = howmany(bp->b_bcount, sdd->sdd_sectsize);
122253901Smckusick
122353901Smckusick /*
122453901Smckusick * When block device is used,
122553901Smckusick * inhibit raw device write operation.
122653901Smckusick */
122753901Smckusick if ((major(bp->b_dev) == sd_c_major) /* RAW I/O */
122853901Smckusick && ((bp->b_flags & B_READ) == 0) /* WRITE */
122953901Smckusick && ((ii->ii_flags & SD_F_ENW) == 0) /* INHIBIT */
123053901Smckusick && ((sd_access_check_on & SD_F_ENW) == 0)) {
123153901Smckusick
123253901Smckusick for (i = 0; i < PNUM; i++) {
123353901Smckusick if (sd_b_openf[unit][i] == 0)
123453901Smckusick continue;
123553901Smckusick /*
123653901Smckusick * |----|========|---|======|-------|
123753901Smckusick * 1 |---+++--------------------------| CUT OFF
123853901Smckusick * 2 |---++++++++++++-----------------| CUT OFF
123953901Smckusick * 3 |---++++++++++++++++-------------| CUT OFF
124053901Smckusick * 4 |---++++++++++++++++++++++++-----| CUT OFF
124153901Smckusick * 5 |-------+++----------------------| ERROR
124253901Smckusick * 6 |------------+++-----------------| ERROR
124353901Smckusick * 7 |------------+++++++-------------| ERROR
124453901Smckusick * 8 |------------+++++++++++++++-----| ERROR
124553901Smckusick */
124653901Smckusick if ((lba < (sizes[i].sd_blkoff + sizes[i].sd_nblocks))
124753901Smckusick && ((lba + sz) > sizes[i].sd_blkoff))
124853901Smckusick check_part |= (1 << i);
124953901Smckusick }
125053901Smckusick }
125153901Smckusick
125253901Smckusick if (check_part) {
125353901Smckusick limit = 0x7fffffff; /* XXX */
125453901Smckusick for (i = 0; i < PNUM; i++) {
125553901Smckusick if ((check_part & (1 << i)) == 0)
125653901Smckusick continue;
125753901Smckusick
125853901Smckusick if (lba >= sizes[i].sd_blkoff) {
125953901Smckusick bp->b_flags |= B_ERROR;
126053901Smckusick bp->b_error = EIO;
126153901Smckusick bp->b_resid = bp->b_bcount;
126253901Smckusick
126353901Smckusick printf("sd%d%c: RAW DEVICE WRITE PROTECTED: ",
126453901Smckusick unit, pname[dev2part(bp->b_dev)]);
126553901Smckusick printf("sn = 0x%x(%d), off = 0x%x(%d)\n",
126653901Smckusick dkblock(bp)*DEV_BSIZE/sdd->sdd_sectsize,
126753901Smckusick dkblock(bp)*DEV_BSIZE/sdd->sdd_sectsize,
126853901Smckusick sizes[dev2part(bp->b_dev)].sd_blkoff,
126953901Smckusick sizes[dev2part(bp->b_dev)].sd_blkoff);
127053901Smckusick
127153901Smckusick return (-1);
127253901Smckusick }
127353901Smckusick
127453901Smckusick if (sizes[i].sd_blkoff < limit)
127553901Smckusick limit = sizes[i].sd_blkoff;
127653901Smckusick }
127753901Smckusick } else {
127853901Smckusick limit = sizes[dev2part(bp->b_dev)].sd_blkoff
127953901Smckusick + sizes[dev2part(bp->b_dev)].sd_nblocks;
128053901Smckusick }
128153901Smckusick
128253901Smckusick if ((over = (lba + sz) - limit) > 0) {
128353901Smckusick /*
128453901Smckusick * Logical Block Address is outside the valid area.
128553901Smckusick */
128653901Smckusick if (((ii->ii_flags & SD_F_EOLBA) != 0)
128753901Smckusick || ((sd_access_check_on & SD_F_EOLBA) != 0)) {
128853901Smckusick /*
128953901Smckusick * error if outside LBA
129053901Smckusick */
129153901Smckusick return(-1);
129253901Smckusick }
129353901Smckusick bp->b_resid = bp->b_bcount - (sz - over) * sdd->sdd_sectsize;
129453901Smckusick if (bp->b_resid >= bp->b_bcount) {
129553901Smckusick bp->b_resid = bp->b_bcount;
129653901Smckusick return(-1);
129753901Smckusick }
129853901Smckusick }
129953901Smckusick
130053901Smckusick return (0);
130153901Smckusick }
130253901Smckusick
sd_b_close(dev,flag)130353901Smckusick sd_b_close(dev, flag)
130453901Smckusick dev_t dev;
130553901Smckusick int flag;
130653901Smckusick {
130753901Smckusick return (_sdclose(dev, flag, S_IFBLK));
130853901Smckusick }
130953901Smckusick
sd_c_close(dev,flag)131053901Smckusick sd_c_close(dev, flag)
131153901Smckusick dev_t dev;
131253901Smckusick int flag;
131353901Smckusick {
131453901Smckusick return (_sdclose(dev, flag, S_IFCHR));
131553901Smckusick }
131653901Smckusick
_sdclose(dev,flag,fmt)131753901Smckusick _sdclose(dev, flag, fmt)
131853901Smckusick register dev_t dev;
131953901Smckusick int flag;
132053901Smckusick int fmt;
132153901Smckusick {
132253901Smckusick register struct iop/**/_device *ii;
132353901Smckusick register struct sdd_softc *sdd;
132453901Smckusick register int unit;
132553901Smckusick struct sdc_softc *sdc;
132653901Smckusick struct scsi uscsi;
132753901Smckusick struct sc_extnd *sce;
132853901Smckusick
132953901Smckusick unit = dev2unit(dev);
133053901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
133153901Smckusick return (ENXIO);
133253901Smckusick
133353901Smckusick sdd = &sdd_softc[unit];
133453901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
133553901Smckusick sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
133653901Smckusick
133753901Smckusick /*
133853901Smckusick * still remain jobs
133953901Smckusick * sleep about 10ms -> 1sec
134053901Smckusick */
134153901Smckusick while (ii->ii_mi->im_tab.b_actf != NULL)
134253901Smckusick sleep((caddr_t)&lbolt, PRIBIO);
134353901Smckusick
134453901Smckusick if ((fmt & S_IFMT) == S_IFBLK)
134553901Smckusick sd_b_openf[unit][dev2part(dev)] = 0;
134653901Smckusick else
134753901Smckusick sd_c_openf[unit][dev2part(dev)] = 0;
134853901Smckusick sdd->sdd_flags &= ~SDDF_XUSE;
134953901Smckusick
135053901Smckusick if ((sdc->sdc_firmware & SDCFW_RMB) && (isalone(unit) == 0)) {
135153901Smckusick sdd->sdd_flags &= ~SDDF_INHRMV;
135253901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
135353901Smckusick uscsi.sc_opcode = SCOP_MEDRMV;
135453901Smckusick uscsi.sc_count = SDRMV_ALLOW;
135553901Smckusick (void) sdcmd(dev, &uscsi);
135653901Smckusick }
135753901Smckusick return (0);
135853901Smckusick }
135953901Smckusick
sdcmd(dev,usc)136053901Smckusick sdcmd(dev, usc)
136153901Smckusick dev_t dev;
136253901Smckusick struct scsi *usc;
136353901Smckusick {
136453901Smckusick register struct buf *bp;
136553901Smckusick register struct scsi *ksc;
136653901Smckusick register u_char *point;
136753901Smckusick register int unit;
136853901Smckusick int error;
136953901Smckusick int s;
137053901Smckusick int cnt;
137153901Smckusick
137253901Smckusick if (usc == 0)
137353901Smckusick return (ENXIO);
137453901Smckusick
137553901Smckusick error = 0;
137653901Smckusick unit = dev2unit(dev);
137753901Smckusick bp = &csdbuf[unit];
137853901Smckusick
137953901Smckusick /*
138053901Smckusick * LOCK csdbuf
138153901Smckusick */
138253901Smckusick s = splclock();
138353901Smckusick while (bp->b_flags & B_BUSY) {
138453901Smckusick bp->b_flags |= B_WANTED;
138553901Smckusick sleep((caddr_t)bp, PRIBIO);
138653901Smckusick }
138753901Smckusick bzero((caddr_t)bp, sizeof(struct buf));
138853901Smckusick bp->b_flags = B_BUSY|B_READ;
138953901Smckusick splx(s);
139053901Smckusick
139153901Smckusick ksc = &kernscsi[unit];
139253901Smckusick bcopy((caddr_t)usc, (caddr_t)ksc, sizeof(struct scsi));
139353901Smckusick /*
139453901Smckusick * setup command buffer
139553901Smckusick */
139653901Smckusick bp->b_dev = dev;
139753901Smckusick bp->b_proc = curproc;
139853901Smckusick cnt = ksc->sc_ctrnscnt;
139953901Smckusick bp->b_bcount = cnt;
140053901Smckusick
140153901Smckusick point = ksc->sc_cpoint;
140253901Smckusick bp->b_un.b_addr = (caddr_t)point;
140353901Smckusick if (cnt > 0) {
140453901Smckusick if (point == NULL) {
140553901Smckusick ksc->sc_cpoint = point = get_scsi(unit)->sc_param;
140653901Smckusick if (cnt > 20) {
140753901Smckusick error = EFAULT;
140853901Smckusick goto done;
140953901Smckusick }
141053901Smckusick }
141153901Smckusick if (point < (u_char *)KERNBASE) {
141253901Smckusick if (useracc(point, cnt, B_WRITE) == NULL) {
141353901Smckusick error = EFAULT;
141453901Smckusick goto done;
141553901Smckusick }
1416*64628Sbostic curproc->p_flag |= P_PHYSIO;
141753901Smckusick vslock(point, cnt);
141853901Smckusick bp->b_flags |= B_PHYS;
141953901Smckusick }
142053901Smckusick #ifndef mips
142153901Smckusick else {
142253901Smckusick if (kernacc(point, cnt, B_WRITE) == NULL) {
142353901Smckusick error = EFAULT;
142453901Smckusick goto done;
142553901Smckusick }
142653901Smckusick }
142753901Smckusick #endif
142853901Smckusick ksc->sc_tstatus = TS_MAPPED_PIO; /* XXX */
142953901Smckusick }
143053901Smckusick
143153901Smckusick /*
143253901Smckusick * call strategy entry, and wait command done.
143353901Smckusick */
143453901Smckusick sdstrategy(bp);
143553901Smckusick iowait(bp);
143653901Smckusick
143753901Smckusick if ((cnt > 0) && (point < (u_char *)KERNBASE)) {
143853901Smckusick vsunlock(point, cnt, B_READ);
1439*64628Sbostic curproc->p_flag &= ~P_PHYSIO;
144053901Smckusick }
144153901Smckusick if ((bp->b_flags & B_ERROR) == 0)
144253901Smckusick error = 0;
144353901Smckusick else {
144453901Smckusick if (bp->b_error)
144553901Smckusick error = bp->b_error;
144653901Smckusick else
144753901Smckusick error = EIO;
144853901Smckusick }
144953901Smckusick bcopy((caddr_t)ksc, (caddr_t)usc, sizeof(struct scsi));
145053901Smckusick
145153901Smckusick done:
145253901Smckusick /*
145353901Smckusick * UNLOCK csdbuf
145453901Smckusick */
145553901Smckusick s = splclock();
145653901Smckusick if (bp->b_flags & B_WANTED)
145753901Smckusick wakeup((caddr_t)bp);
145853901Smckusick bp->b_flags = 0;
145953901Smckusick splx(s);
146053901Smckusick return (error);
146153901Smckusick }
146253901Smckusick
146353901Smckusick /*
146453901Smckusick * read partition information from sector zero.
146553901Smckusick */
sdrpartinfo(ii)146653901Smckusick sdrpartinfo(ii)
146753901Smckusick register struct iop/**/_device *ii;
146853901Smckusick {
146953901Smckusick register struct disklabel *dlp;
147053901Smckusick register struct sdst *hsp;
147153901Smckusick register struct sdst *st;
147253901Smckusick register int unit;
147353901Smckusick register int i;
147453901Smckusick struct firstsector *fsp;
147553901Smckusick struct sdc_softc *sdc;
147653901Smckusick struct sdd_softc *sdd;
147753901Smckusick struct sddevinfo *sdi;
147853901Smckusick struct scsi uscsi;
147953901Smckusick int s;
148053901Smckusick
148153901Smckusick sdi = &sddevinfo[ii->ii_type];
148253901Smckusick unit = ii->ii_unit;
148353901Smckusick
148453901Smckusick sdd = &sdd_softc[unit];
148553901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
148653901Smckusick
148753901Smckusick if ((sdd->sdd_flags & (SDDF_NONFMT|SDDF_FMTDONE)) == 0) {
148853901Smckusick register struct sc_rcap *scr = (struct sc_rcap *)sdtmp;
148953901Smckusick
149053901Smckusick sdd->sdd_flags |= SDDF_FMTDONE;
149153901Smckusick
149253901Smckusick bzero((caddr_t)sdtmp, 8);
149353901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
149453901Smckusick uscsi.sc_cpoint = (u_char *)scr;
149553901Smckusick uscsi.sc_ctrnscnt = 8;
149653901Smckusick uscsi.sc_opcode = SCOP_RCAP;
149753901Smckusick (void) sdcmd(unit << 3, &uscsi);
149853901Smckusick
149953901Smckusick sdd->sdd_nsect = scr->scr_nblock + 1;
150053901Smckusick sdd->sdd_sectsize = scr->scr_blocklen;
150153901Smckusick if (sdd->sdd_sectsize == 0)
150253901Smckusick sdd->sdd_sectsize = SDBSIZE1K;
150353901Smckusick }
150453901Smckusick
150553901Smckusick bzero(sdtmp, DEV_BSIZE);
150653901Smckusick
150753901Smckusick if ((sdd->sdd_flags & SDDF_NONFMT) == 0) {
150853901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
150953901Smckusick uscsi.sc_cpoint = sdtmp;
151053901Smckusick uscsi.sc_ctrnscnt = DEV_BSIZE;
151153901Smckusick uscsi.sc_opcode = SCOP_READ;
151253901Smckusick uscsi.sc_lad = 0;
151353901Smckusick uscsi.sc_count = 1;
151453901Smckusick
151553901Smckusick (void) sdcmd(unit << 3, &uscsi);
151653901Smckusick sdd->sdd_flags &= ~SDDF_SKIPCHECK;
151753901Smckusick }
151853901Smckusick
151953901Smckusick fsp = (struct firstsector *)sdtmp;
152053901Smckusick dlp = (struct disklabel *)(sdtmp + LABELOFFSET);
152153901Smckusick
152253901Smckusick s = splclock();
152353901Smckusick hsp = &sdstdrv[unit];
152453901Smckusick bzero((caddr_t)hsp, sizeof (struct sdst));
152553901Smckusick bzero(&sdlabel[unit], sizeof (struct disklabel));
152653901Smckusick
152753901Smckusick if ((dlp->d_magic == DISKMAGIC)
152853901Smckusick && ((ii->ii_flags & SD_F_IGNLABEL) == 0)) {
152953901Smckusick sdlabel[unit] = *dlp;
153053901Smckusick disklabel2sdst(unit, dlp, hsp);
153153901Smckusick } else {
153253901Smckusick if ((ii->ii_type == UNKNOWN_DISK)
153353901Smckusick || (sdi->sdstp->sizes == calc_disk_sizes)) {
153453901Smckusick /*
153553901Smckusick * If device is UNKNOWN PARTITION SIZE,
153653901Smckusick * calculate default partition from capacity.
153753901Smckusick */
153853901Smckusick st = sdi->sdstp;
153953901Smckusick hsp->nsect = st->nsect; /* # sectors/track */
154053901Smckusick hsp->ntrak = st->ntrak; /* # tracks/cylinder */
154153901Smckusick hsp->nspc = st->nspc; /* # sectors/cylinder */
154253901Smckusick hsp->ncyl = st->ncyl; /* # cylinders */
154353901Smckusick hsp->rps = st->rps; /* # revolutions/sec */
154453901Smckusick hsp->sizes = sdsizedrv[unit]; /* partition table */
154553901Smckusick
154653901Smckusick sd_calcpart(ii, hsp->sizes,
154753901Smckusick sdd->sdd_nsect, sdd->sdd_sectsize);
154853901Smckusick sdst2disklabel(unit, hsp, &sdlabel[unit]);
154953901Smckusick } else {
155053901Smckusick /*
155153901Smckusick * If device is support disk,
155253901Smckusick * copy default partition from size table.
155353901Smckusick */
155453901Smckusick st = sdi->sdstp;
155553901Smckusick
155653901Smckusick hsp->nsect = st->nsect; /* # sectors/track */
155753901Smckusick hsp->ntrak = st->ntrak; /* # tracks/cylinder */
155853901Smckusick hsp->nspc = st->nspc; /* # sectors/cylinder */
155953901Smckusick hsp->ncyl = st->ncyl; /* # cylinders */
156053901Smckusick hsp->rps = st->rps; /* # revolutions / second */
156153901Smckusick hsp->sizes = sdsizedrv[unit]; /* partition table */
156253901Smckusick
156353901Smckusick for (i = 0; i < PNUM; i++) {
156453901Smckusick hsp->sizes[i].sd_nblocks = st->sizes[i].sd_nblocks;
156553901Smckusick hsp->sizes[i].sd_blkoff = st->sizes[i].sd_blkoff;
156653901Smckusick }
156753901Smckusick sdst2disklabel(unit, hsp, &sdlabel[unit]);
156853901Smckusick }
156953901Smckusick }
157053901Smckusick
157153901Smckusick /* BEGIN XXX*/
157253901Smckusick if (hsp->rps == 0) {
157353901Smckusick /*
157453901Smckusick * If device is support disk,
157553901Smckusick * copy default partition from size table.
157653901Smckusick */
157753901Smckusick st = sdi->sdstp;
157853901Smckusick
157953901Smckusick hsp->nsect = st->nsect; /* # sectors/track */
158053901Smckusick hsp->ntrak = st->ntrak; /* # tracks/cylinder */
158153901Smckusick hsp->nspc = st->nspc; /* # sectors/cylinder */
158253901Smckusick hsp->ncyl = st->ncyl; /* # cylinders */
158353901Smckusick hsp->rps = st->rps; /* # revolutions / second */
158453901Smckusick sdst2disklabel(unit, hsp, &sdlabel[unit]);
158553901Smckusick }
158653901Smckusick /* END XXX*/
158753901Smckusick (void)splx(s);
158853901Smckusick }
158953901Smckusick
159053901Smckusick static char Warn_Part[] = "sd%d: PARTITION TABLE CHANGED\n";
159153901Smckusick static char Pr_Part_Fmt[] = "sd%d%c: nblk=%d, off=%d\n";
159253901Smckusick
159353901Smckusick #define stsz(N) st->sizes[(N)].sd_nblocks
159453901Smckusick #define stof(N) st->sizes[(N)].sd_blkoff
159553901Smckusick #define dlsz(N) dlp->d_partitions[(N)].p_size
159653901Smckusick #define dlof(N) dlp->d_partitions[(N)].p_offset
159753901Smckusick #define disz(N) dip->di_part[(N)].dp_nblocks
159853901Smckusick #define diof(N) dip->di_part[(N)].dp_blkoff
159953901Smckusick
160053901Smckusick #ifndef BBSIZE
160153901Smckusick #define BBSIZE 8192
160253901Smckusick #endif
160353901Smckusick
160453901Smckusick static
check_sdst(unit,st)160553901Smckusick check_sdst(unit, st)
160653901Smckusick int unit;
160753901Smckusick struct sdst *st;
160853901Smckusick {
160953901Smckusick if (st->nsect == 0) {
161053901Smckusick st->nsect = 1;
161153901Smckusick printf("sd%d: nsect SHOULD BE != 0, 1 assumed\n", unit);
161253901Smckusick }
161353901Smckusick
161453901Smckusick if (st->rps == 0) {
161553901Smckusick st->rps = 60;
161653901Smckusick printf("sd%d: rps SHOULD BE != 0, 60 assumed\n", unit);
161753901Smckusick }
161853901Smckusick }
161953901Smckusick
162053901Smckusick static
disklabel2sdst(unit,dlp,st)162153901Smckusick disklabel2sdst(unit, dlp, st)
162253901Smckusick int unit;
162353901Smckusick register struct disklabel *dlp;
162453901Smckusick register struct sdst *st;
162553901Smckusick {
162653901Smckusick register int i;
162753901Smckusick int msg_header_printed;
162853901Smckusick
162953901Smckusick msg_header_printed = 0;
163053901Smckusick
163153901Smckusick st->nsect = dlp->d_nsectors; /* # sectors/track */
163253901Smckusick st->ntrak = dlp->d_ntracks; /* # tracks/cylinder */
163353901Smckusick st->nspc = dlp->d_secpercyl; /* # sectors/cylinder */
163453901Smckusick st->ncyl = dlp->d_ncylinders; /* # cylinders */
163553901Smckusick st->rps = dlp->d_rpm / 60; /* # revolutions / second */
163653901Smckusick st->sizes = sdsizedrv[unit]; /* partition table */
163753901Smckusick
163853901Smckusick check_sdst(unit, st);
163953901Smckusick
164053901Smckusick for (i = 0; i < PNUM; i++) {
164153901Smckusick if (msg_header_printed == 0) {
164253901Smckusick if (((stsz(i) != 0) || (stof(i) != 0))
164353901Smckusick && ((stsz(i) != dlsz(i)) || (stof(i) != dlof(i)))) {
164453901Smckusick msg_header_printed = 1;
164553901Smckusick }
164653901Smckusick }
164753901Smckusick }
164853901Smckusick
164953901Smckusick for (i = 0; i < PNUM; i++) {
165053901Smckusick stsz(i) = dlsz(i);
165153901Smckusick stof(i) = dlof(i);
165253901Smckusick }
165353901Smckusick
165453901Smckusick if (msg_header_printed) {
165553901Smckusick printf(Warn_Part, unit);
165653901Smckusick for (i = 0; i < PNUM; i++)
165753901Smckusick printf(Pr_Part_Fmt, unit, pname[i], stsz(i), stof(i));
165853901Smckusick }
165953901Smckusick }
166053901Smckusick
166153901Smckusick static
sdst2disklabel(unit,st,dlp)166253901Smckusick sdst2disklabel(unit, st, dlp)
166353901Smckusick int unit; /*XXX*/
166453901Smckusick register struct sdst *st;
166553901Smckusick register struct disklabel *dlp;
166653901Smckusick {
166753901Smckusick register int i;
166853901Smckusick
166953901Smckusick dlp->d_type = DTYPE_SCSI; /* drive type */
167053901Smckusick dlp->d_secsize = sdd_softc[unit].sdd_sectsize; /* # of bytes per sector */
167153901Smckusick dlp->d_nsectors = st->nsect; /* # sectors/track */
167253901Smckusick dlp->d_ntracks = st->ntrak; /* # tracks/cylinder */
167353901Smckusick dlp->d_ncylinders = st->ncyl; /* # cylinders */
167453901Smckusick dlp->d_secpercyl = st->nspc; /* # sectors/cylinder */
167553901Smckusick dlp->d_rpm = st->rps * 60; /* # revolutions / minute */
167653901Smckusick dlp->d_bbsize = BBSIZE; /*XXX*/ /* size of boot area at sn0, bytes */
167753901Smckusick dlp->d_sbsize = SBSIZE; /*XXX*/ /* max size of fs superblock, bytes */
167853901Smckusick
167953901Smckusick for (i = 0; i < PNUM; i++) {
168053901Smckusick dlsz(i) = stsz(i);
168153901Smckusick dlof(i) = stof(i);
168253901Smckusick }
168353901Smckusick }
168453901Smckusick
168553901Smckusick #undef stsz
168653901Smckusick #undef stof
168753901Smckusick #undef dlsz
168853901Smckusick #undef dlof
168953901Smckusick #undef disz
169053901Smckusick #undef diof
169153901Smckusick
sd_calcpart(ii,disk_sizes,nsect,sectsize)169253901Smckusick sd_calcpart(ii, disk_sizes, nsect, sectsize)
169353901Smckusick register struct iop/**/_device *ii;
169453901Smckusick register struct size disk_sizes[];
169553901Smckusick int nsect;
169653901Smckusick int sectsize;
169753901Smckusick {
169853901Smckusick register struct defpart *dp;
169953901Smckusick register int size_mb;
170053901Smckusick register int i;
170153901Smckusick int psize;
170253901Smckusick
170353901Smckusick size_mb = nsect * sectsize / (1024 * 1024);
170453901Smckusick
170553901Smckusick for (dp = defpart_std; dp->range_max; dp++)
170653901Smckusick if ((dp->range_min <= size_mb) && (size_mb < dp->range_max))
170753901Smckusick break;
170853901Smckusick
170953901Smckusick /* PASS1 */
171053901Smckusick for (i = 0; i < PNUM; i++) {
171153901Smckusick psize = dp->partsize[i];
171253901Smckusick
171353901Smckusick switch (psize) {
171453901Smckusick
171553901Smckusick case PART_UNUSED:
171653901Smckusick disk_sizes[i].sd_nblocks = 0;
171753901Smckusick break;
171853901Smckusick
171953901Smckusick case PART_SPEC:
172053901Smckusick disk_sizes[i].sd_nblocks = nsect * sectsize / DEV_BSIZE;
172153901Smckusick break;
172253901Smckusick
172353901Smckusick case PART_CALCF:
172453901Smckusick case PART_CALCG:
172553901Smckusick break;
172653901Smckusick
172753901Smckusick default:
172853901Smckusick disk_sizes[i].sd_nblocks = psize;
172953901Smckusick break;
173053901Smckusick }
173153901Smckusick }
173253901Smckusick
173353901Smckusick /* PASS2 */
173453901Smckusick for (i = 0; i < PNUM; i++) {
173553901Smckusick psize = dp->partsize[i];
173653901Smckusick
173753901Smckusick switch (psize) {
173853901Smckusick
173953901Smckusick case PART_UNUSED:
174053901Smckusick case PART_SPEC:
174153901Smckusick break;
174253901Smckusick
174353901Smckusick case PART_CALCF:
174453901Smckusick disk_sizes[i].sd_nblocks =
174553901Smckusick disk_sizes[PART_C].sd_nblocks -
174653901Smckusick (disk_sizes[PART_A].sd_nblocks +
174753901Smckusick disk_sizes[PART_B].sd_nblocks +
174853901Smckusick disk_sizes[PART_D].sd_nblocks +
174953901Smckusick disk_sizes[PART_E].sd_nblocks +
175053901Smckusick disk_sizes[PART_H].sd_nblocks);
175153901Smckusick break;
175253901Smckusick
175353901Smckusick case PART_CALCG:
175453901Smckusick disk_sizes[i].sd_nblocks =
175553901Smckusick disk_sizes[PART_C].sd_nblocks -
175653901Smckusick (disk_sizes[PART_A].sd_nblocks +
175753901Smckusick disk_sizes[PART_B].sd_nblocks +
175853901Smckusick disk_sizes[PART_H].sd_nblocks);
175953901Smckusick break;
176053901Smckusick
176153901Smckusick default:
176253901Smckusick break;
176353901Smckusick }
176453901Smckusick }
176553901Smckusick
176653901Smckusick /* OFFSET */
176753901Smckusick disk_sizes[PART_A].sd_blkoff = 0;
176853901Smckusick disk_sizes[PART_B].sd_blkoff = disk_sizes[PART_A].sd_nblocks;
176953901Smckusick disk_sizes[PART_C].sd_blkoff = 0;
177053901Smckusick disk_sizes[PART_D].sd_blkoff = disk_sizes[PART_A].sd_nblocks
177153901Smckusick + disk_sizes[PART_B].sd_nblocks
177253901Smckusick + disk_sizes[PART_H].sd_nblocks;
177353901Smckusick disk_sizes[PART_E].sd_blkoff = disk_sizes[PART_D].sd_blkoff
177453901Smckusick + disk_sizes[PART_D].sd_nblocks;
177553901Smckusick disk_sizes[PART_F].sd_blkoff = disk_sizes[PART_E].sd_blkoff
177653901Smckusick + disk_sizes[PART_E].sd_nblocks;
177753901Smckusick disk_sizes[PART_G].sd_blkoff = disk_sizes[PART_D].sd_blkoff;
177853901Smckusick
177953901Smckusick if (disk_sizes[PART_H].sd_nblocks == 0)
178053901Smckusick disk_sizes[PART_H].sd_blkoff = 0;
178153901Smckusick else {
178253901Smckusick disk_sizes[PART_H].sd_blkoff =
178353901Smckusick disk_sizes[PART_A].sd_nblocks +
178453901Smckusick disk_sizes[PART_B].sd_nblocks;
178553901Smckusick }
178653901Smckusick
178753901Smckusick for (i = 0; i < PNUM; i++)
178853901Smckusick if (disk_sizes[i].sd_nblocks == 0)
178953901Smckusick disk_sizes[i].sd_blkoff = 0;
179053901Smckusick }
179153901Smckusick
179253901Smckusick int sd_str_pr = 0;
179353901Smckusick
sdstrategy(bp)179453901Smckusick sdstrategy(bp)
179553901Smckusick register struct buf *bp;
179653901Smckusick {
179753901Smckusick register struct iop/**/_device *ii;
179853901Smckusick register struct sdst *st;
179953901Smckusick register struct buf *dp;
180053901Smckusick register int unit;
180153901Smckusick register int ssize;
180253901Smckusick struct sdd_softc *sdd;
180353901Smckusick struct sdc_softc *sdc;
180453901Smckusick long bn;
180553901Smckusick int xunit;
180653901Smckusick int s;
180753901Smckusick
180853901Smckusick xunit = dev2part(bp->b_dev);
180953901Smckusick unit = dev2unit(bp->b_dev);
181053901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
181153901Smckusick goto bad;
181253901Smckusick
181353901Smckusick if (bp != &csdbuf[unit]) {
181453901Smckusick /*
181553901Smckusick * READ / WRITE command
181653901Smckusick */
181753901Smckusick sdd = &sdd_softc[unit];
181853901Smckusick if (sdd->sdd_flags & SDDF_NONFMT)
181953901Smckusick goto bad;
182053901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
182153901Smckusick ssize = sdd->sdd_sectsize;
182253901Smckusick if ((ssize != DEV_BSIZE)
182353901Smckusick && ((((dkblock(bp) * DEV_BSIZE) % ssize) != 0)
182453901Smckusick || (((bp->b_flags & B_READ) == 0) &&
182553901Smckusick ((bp->b_bcount % ssize) != 0)))) {
182653901Smckusick goto bad;
182753901Smckusick }
182853901Smckusick
182953901Smckusick st = &sdstdrv[unit];
183053901Smckusick bn = dkblock(bp);
183153901Smckusick bp->b_resid = 0;
183253901Smckusick if ((bn < 0) || (bn >= st->sizes[xunit].sd_nblocks))
183353901Smckusick goto bad2;
183453901Smckusick if (sd_access_check(bp) < 0)
183553901Smckusick goto bad2;
183653901Smckusick
183753901Smckusick #ifdef notdef /* KU: XXX */
183853901Smckusick bp->b_cylin = (bn + st->sizes[xunit].sd_blkoff) / st->nspc;
183953901Smckusick } else {
184053901Smckusick bp->b_cylin = 0;
184153901Smckusick #endif
184253901Smckusick }
184353901Smckusick
184453901Smckusick s = splsc();
184553901Smckusick dp = &sdutab[ii->ii_unit];
184653901Smckusick disksort(dp, bp);
184753901Smckusick if (dp->b_active == 0) {
184853901Smckusick sdustart(ii);
184953901Smckusick bp = &ii->ii_mi->im_tab;
185053901Smckusick if (bp->b_actf && bp->b_active == 0)
185153901Smckusick sdstart(ii->ii_mi);
185253901Smckusick }
185353901Smckusick splx(s);
185453901Smckusick return;
185553901Smckusick
185653901Smckusick bad:
185753901Smckusick bp->b_flags |= B_ERROR;
185853901Smckusick goto done;
185953901Smckusick bad2:
186053901Smckusick bp->b_resid = bp->b_bcount;
186153901Smckusick done:
186253901Smckusick iodone(bp);
186353901Smckusick }
186453901Smckusick
186553901Smckusick /*
186653901Smckusick * Unit start routine.
186753901Smckusick */
sdustart(ii)186853901Smckusick sdustart(ii)
186953901Smckusick register struct iop/**/_device *ii;
187053901Smckusick {
187153901Smckusick register struct iop/**/_ctlr *im;
187253901Smckusick register struct buf *dp;
187353901Smckusick
187453901Smckusick if (ii == NULL)
187553901Smckusick return;
187653901Smckusick im = ii->ii_mi;
187753901Smckusick dk_busy &= ~(1 << ii->ii_dk);
187853901Smckusick dp = &sdutab[ii->ii_unit];
187953901Smckusick if (dp->b_actf == NULL)
188053901Smckusick return;
188153901Smckusick /*
188253901Smckusick * If the controller is active, just remember
188353901Smckusick * that this device would like to be positioned ...
188453901Smckusick * if we tried to position now we would confuse the SD.
188553901Smckusick */
188653901Smckusick if (im->im_tab.b_active) {
188753901Smckusick sdc_softc[im->im_ctlr].sdc_softas |= (1 << ii->ii_slave);
188853901Smckusick return;
188953901Smckusick }
189053901Smckusick /*
189153901Smckusick * If we have already positioned this drive,
189253901Smckusick * then just put it on the ready queue.
189353901Smckusick */
189453901Smckusick if (dp->b_active == 0)
189553901Smckusick dp->b_active = 1;
189653901Smckusick /*
189753901Smckusick * Device is ready to go
189853901Smckusick * put it on the ready queue for the controller
189953901Smckusick * (unless its already there.)
190053901Smckusick */
190153901Smckusick if (dp->b_active != 2) {
190257612Sutashiro im->im_tab.b_actf = dp;
190353901Smckusick dp->b_active = 2;
190453901Smckusick }
190553901Smckusick }
190653901Smckusick
190753901Smckusick /*
190853901Smckusick * Start up a transfer on a drive.
190953901Smckusick */
sdstart(im)191053901Smckusick sdstart(im)
191153901Smckusick register struct iop/**/_ctlr *im;
191253901Smckusick {
191353901Smckusick register struct buf *bp;
191453901Smckusick register struct buf *dp;
191553901Smckusick register struct sdc_softc *sdc;
191653901Smckusick
191753901Smckusick loop:
191853901Smckusick /*
191953901Smckusick * Pull a request off the controller queue.
192053901Smckusick */
192153901Smckusick if ((dp = im->im_tab.b_actf) == NULL)
192253901Smckusick return;
192357612Sutashiro if ((bp = dp->b_actf) == NULL)
192457612Sutashiro return;
192553901Smckusick /*
192653901Smckusick * Mark controller busy, and
192753901Smckusick * determine destination of this request.
192853901Smckusick */
192953901Smckusick im->im_tab.b_active++;
193053901Smckusick
193153901Smckusick sdexec(bp);
193253901Smckusick }
193353901Smckusick
193453901Smckusick void
sdexec(bp)193553901Smckusick sdexec(bp)
193653901Smckusick register struct buf *bp;
193753901Smckusick {
193853901Smckusick register struct iop/**/_device *ii;
193953901Smckusick register struct buf_stat *bs;
194053901Smckusick register struct scsi *sc;
194153901Smckusick register int ssize;
194253901Smckusick register int unit;
194353901Smckusick register int intr;
194453901Smckusick register int bn;
194553901Smckusick struct sdc_softc *sdc;
194653901Smckusick struct sdd_softc *sdd;
194753901Smckusick struct sdst *st;
194853901Smckusick int sz;
194953901Smckusick int over;
195053901Smckusick struct sc_map *map;
195153901Smckusick
195253901Smckusick unit = dev2unit(bp->b_dev);
195357612Sutashiro ii = sddinfo[unit];
195453901Smckusick intr = ii->ii_intr;
195553901Smckusick sdd = &sdd_softc[unit];
195653901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
195753901Smckusick
195853901Smckusick sc = get_scsi(intr);
195953901Smckusick
196053901Smckusick if (bp == &csdbuf[unit]) { /* do sdcmd() */
196153901Smckusick bcopy((caddr_t)&kernscsi[unit],
196253901Smckusick (caddr_t)sc, sizeof(struct scsi));
196353901Smckusick if (bp->b_un.b_addr == NULL) {
196453901Smckusick map = 0;
196553901Smckusick } else {
196653901Smckusick map = get_sc_map(intr);
196753901Smckusick sc->sc_map = (struct sc_map *)ipc_phys(map);
196853901Smckusick }
196953901Smckusick } else { /* R/W */
197053901Smckusick ssize = sdd->sdd_sectsize;
197153901Smckusick
197253901Smckusick st = &sdstdrv[unit];
197353901Smckusick bn = dkblock(bp);
197453901Smckusick if (sdd->sdd_lastblk / st->nspc != bn / st->nspc)
197553901Smckusick dk_seek[ii->ii_dk]++;
197653901Smckusick
197753901Smckusick st = &sdstdrv[unit];
197853901Smckusick bn = dkblock(bp);
197953901Smckusick
198053901Smckusick /*
198153901Smckusick * Setup for the transfer, and get in the IOP queue.
198253901Smckusick */
198353901Smckusick scinit(sc, ii->ii_slave, ssize);
198453901Smckusick sc->sc_ctrnscnt = bp->b_bcount - bp->b_resid;
198553901Smckusick map = get_sc_map(intr);
198653901Smckusick sc->sc_map = (struct sc_map *)ipc_phys(map);
198753901Smckusick
198853901Smckusick /* cdb */
198953901Smckusick sc->sc_cdb.un_type1.t1_opcode =
199053901Smckusick (bp->b_flags & B_READ) ? SCOP_EREAD :
199153901Smckusick (ii->ii_flags & SD_F_WRTVRFY) ? SCOP_WRTVRFY :
199253901Smckusick SCOP_EWRITE;
199353901Smckusick #ifdef mips
199453901Smckusick {
199553901Smckusick int v;
199653901Smckusick
199753901Smckusick v = (bn + st->sizes[dev2part(bp->b_dev)].sd_blkoff)
199853901Smckusick * DEV_BSIZE / sdd->sdd_sectsize;
199953901Smckusick sc->sc_ladhi = v >> 16;
200053901Smckusick sc->sc_ladlo = v;
200153901Smckusick
200253901Smckusick v = (sc->sc_ctrnscnt + ssize - 1) / ssize;
200353901Smckusick sc->sc_cdb.un_type1.t1_p2 = v >> 8;
200453901Smckusick sc->sc_cdb.un_type1.t1_p3 = v;
200553901Smckusick }
200653901Smckusick #else
200753901Smckusick *(u_int *)(&sc->sc_cdb.un_type1.t1_ladhi) =
200853901Smckusick (bn + st->sizes[dev2part(bp->b_dev)].sd_blkoff)
200953901Smckusick * DEV_BSIZE / sdd->sdd_sectsize;
201053901Smckusick *(u_short *)(&sc->sc_cdb.un_type1.t1_p2) =
201153901Smckusick (sc->sc_ctrnscnt + ssize -1) / ssize;
201253901Smckusick #endif
201353901Smckusick if ((sdd->sdd_flags & SDDF_ERASEOFF)
201453901Smckusick && ((bp->b_flags & B_READ) == 0)) {
201553901Smckusick sc->sc_ctrl = 0x40;
201653901Smckusick }
201753901Smckusick }
201853901Smckusick
201953901Smckusick sdc->sdc_firmware |= SDCFW_BUSY;
202053901Smckusick iop/**/go(ii, map);
202153901Smckusick }
202253901Smckusick
202353901Smckusick /*
202453901Smckusick * Now all ready to go.
202553901Smckusick */
sddgo(im)202653901Smckusick sddgo(im)
202753901Smckusick register struct iop/**/_ctlr *im;
202853901Smckusick {
202953901Smckusick register int intr;
203053901Smckusick
203153901Smckusick im->im_tab.b_active = 2;
203253901Smckusick intr = im->im_intr;
203353901Smckusick
203453901Smckusick sc_go(intr, get_scsi(intr), SCSI_INTEN);
203553901Smckusick }
203653901Smckusick
203753901Smckusick /*
203853901Smckusick * copyin(), copyout() can't use in the interrupt routine.
203953901Smckusick * because user process is changed.
204053901Smckusick */
204153901Smckusick /*
204253901Smckusick * Handle a disk interrupt.
204353901Smckusick * d: controller number
204453901Smckusick */
sdintr(d)204553901Smckusick sdintr(d)
204653901Smckusick int d;
204753901Smckusick {
204853901Smckusick register struct iop/**/_ctlr *im;
204953901Smckusick register struct sdc_softc *sdc;
205053901Smckusick register struct sdd_softc *sdd;
205153901Smckusick register struct scsi *sc;
205253901Smckusick register int intr;
205353901Smckusick register int unit;
205453901Smckusick register int slave;
205553901Smckusick register int as;
205653901Smckusick struct iop/**/_device *ii;
205753901Smckusick struct sddevinfo *sdi;
205853901Smckusick struct sc_extnd *sce;
205953901Smckusick struct sdst *st;
206053901Smckusick struct buf *bp;
206153901Smckusick struct buf *dp;
206253901Smckusick char *erp_page;
206353901Smckusick int code;
206453901Smckusick int len;
206553901Smckusick int tstatus;
206653901Smckusick int delay_start();
206753901Smckusick int delay_medrmv();
206853901Smckusick int wait_re_init_done();
206953901Smckusick
207053901Smckusick im = sdminfo[d];
207153901Smckusick sdc = &sdc_softc[im->im_ctlr];
207253901Smckusick intr = im->im_intr;
207353901Smckusick as = sdc->sdc_softas;
207453901Smckusick
207553901Smckusick sdc->sdc_wticks = 0;
207653901Smckusick sc = get_scsi(intr);
207753901Smckusick /*
207853901Smckusick * If SDCS_IOCTL bit is set, then don't check error.
207953901Smckusick */
208053901Smckusick if (sdc->sdc_state & SDCS_IOCTL) {
208153901Smckusick sdc->sdc_state &= ~SDCS_IOCTL;
208253901Smckusick sdd = &sdd_softc[(sdip[d][sc->sc_identify & IDT_DRMASK])->ii_unit];
208353901Smckusick
208453901Smckusick if (sdc->sdc_state & SDCS_SCUNLOCK) {
208553901Smckusick int s;
208653901Smckusick
208753901Smckusick sdc->sdc_state &= ~SDCS_SCUNLOCK;
208853901Smckusick s = splclock();
208953901Smckusick if (sdc->sdc_state & SDCS_OPEN_WAIT) {
209053901Smckusick sdc->sdc_state &= ~SDCS_OPEN_WAIT;
209153901Smckusick wakeup((caddr_t)sdc);
209253901Smckusick }
209353901Smckusick splx(s);
209453901Smckusick /*
209553901Smckusick * UNLOCK SCSI access
209653901Smckusick */
209753901Smckusick sdc->sdc_firmware &= ~SDCFW_BUSY;
209853901Smckusick }
209953901Smckusick return;
210053901Smckusick }
210153901Smckusick
210253901Smckusick im->im_tab.b_active = 1;
210353901Smckusick /*
210453901Smckusick * Get device and block structures, and a pointer
210553901Smckusick * to the iop_device for the drive.
210653901Smckusick */
210753901Smckusick dp = im->im_tab.b_actf;
210853901Smckusick bp = dp->b_actf;
210953901Smckusick unit = dev2unit(bp->b_dev);
211053901Smckusick
211153901Smckusick ii = sddinfo[unit];
211253901Smckusick slave = ii->ii_slave;
211353901Smckusick st = &sdstdrv[unit];
211453901Smckusick dk_busy &= ~(1 << ii->ii_dk);
211553901Smckusick sdd = &sdd_softc[unit];
211653901Smckusick sdi = &sddevinfo[ii->ii_type];
211753901Smckusick sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
211853901Smckusick
211953901Smckusick /*
212053901Smckusick * Check error on the drive.
212153901Smckusick */
212253901Smckusick tstatus = sc->sc_tstatus & TGSTMASK;
212353901Smckusick if (sc->sc_istatus != INST_EP) {
212453901Smckusick /*
212553901Smckusick * initiator status is bad.
212653901Smckusick * check & retry !!
212753901Smckusick */
212853901Smckusick if ((sc->sc_istatus&(INST_EP|INST_PRE)) == (INST_EP|INST_PRE)) {
212953901Smckusick /* detect parity error or abnormal terminate */
213053901Smckusick if ((sc->sc_istatus & INST_LB) == 0)
213153901Smckusick printf("sd%d: SCSI bus parity error\n", unit);
213253901Smckusick sdc->sdc_countcc--;
213353901Smckusick goto sdintr_exec;
213453901Smckusick }
213553901Smckusick if ((sc->sc_istatus & INST_EP) == 0) {
213653901Smckusick if (sc->sc_istatus & (INST_WAIT | INST_IP | INST_WR)) {
213753901Smckusick if (++sdc->sdc_retrycnt < NRETRY) {
213853901Smckusick im->im_tab.b_active = 2;
213953901Smckusick /*
214053901Smckusick * Konomama return sitemo,
214153901Smckusick * lost interrupt ni narudake deha
214253901Smckusick * naidarou ka ?
214353901Smckusick * Isso error ni sitahou ga
214453901Smckusick * ii nodeha naidarou ka ?
214553901Smckusick */
214653901Smckusick return;
214753901Smckusick }
214853901Smckusick }
214953901Smckusick printf("SCSI%d: abnormal termination\n", intr);
215053901Smckusick printf("ISTAT = 0x%x, TSTAT = 0x%x\n",
215153901Smckusick sc->sc_istatus, sc->sc_tstatus);
215253901Smckusick if (++sdc->sdc_nhrderr >= MAXHRDERR) {
215353901Smckusick printf("SCSI%d: too many hard errors\n", intr);
215453901Smckusick sdc->sdc_nhrderr = 0;
215553901Smckusick goto sdintr_error;
215653901Smckusick }
215753901Smckusick screset(intr);
215853901Smckusick goto sdintr_exec;
215953901Smckusick }
216053901Smckusick if ((sc->sc_istatus & (INST_TO|INST_HE)) != 0) {
216153901Smckusick if (sc->sc_istatus & INST_HE) {
216253901Smckusick /*
216353901Smckusick * SCSI bus reset is occured.
216453901Smckusick * to be continue --> hdreset()
216553901Smckusick */
216653901Smckusick re_init_done = 0;
216753901Smckusick timeout(wait_re_init_done, bp, 10*hz);
216853901Smckusick return;
216953901Smckusick }
217053901Smckusick if (++sdc->sdc_nhrderr >= MAXHRDERR) {
217153901Smckusick printf("SCSI%d: too many hard errors (ISTAT=0x%x)\n",
217253901Smckusick intr, sc->sc_istatus);
217353901Smckusick sdc->sdc_nhrderr = 0;
217453901Smckusick goto sdintr_error;
217553901Smckusick }
217653901Smckusick if (++sdc->sdc_retrycnt >= NRETRY) {
217753901Smckusick printf("SCSI%d: too many initiator errors (ISTAT=0x%x)\n",
217853901Smckusick intr, sc->sc_istatus);
217953901Smckusick goto sdintr_error;
218053901Smckusick }
218153901Smckusick DELAY(D100MSEC * 10);
218253901Smckusick goto sdintr_exec;
218353901Smckusick }
218453901Smckusick }
218553901Smckusick
218653901Smckusick if (sdd->sdd_flags & SDDF_SKIPCHECK)
218753901Smckusick goto sdintr_done;
218853901Smckusick
218953901Smckusick check_target_status:
219053901Smckusick /*
219153901Smckusick * check target status
219253901Smckusick */
219353901Smckusick switch (sdc->sdc_state) {
219453901Smckusick
219553901Smckusick /********************************/
219653901Smckusick /* */
219753901Smckusick /* NORMAL OPERATION */
219853901Smckusick /* */
219953901Smckusick /********************************/
220053901Smckusick case SDCS_NORMAL:
220153901Smckusick switch (tstatus) {
220253901Smckusick
220353901Smckusick case TGST_GOOD:
220453901Smckusick break;
220553901Smckusick
220653901Smckusick case TGST_CC:
220753901Smckusick sdc->sdc_state |= SDCS_RSENSE;
220853901Smckusick sdintr_rsense:
220953901Smckusick im->im_tab.b_active = 2;
221053901Smckusick bzero((caddr_t)sce, RSEN_CNT);
221153901Smckusick scop_rsense(intr, sc, slave,
221253901Smckusick SCSI_INTEN, RSEN_CNT, (caddr_t)sce);
221353901Smckusick return;
221453901Smckusick
221553901Smckusick case TGST_BUSY:
221653901Smckusick if (++sdc->sdc_retrycnt > MAXRETRYCNT) {
221753901Smckusick goto sdintr_error;
221853901Smckusick }
221953901Smckusick timeout(sdexec, (caddr_t)bp, hz);
222053901Smckusick return;
222153901Smckusick
222253901Smckusick default:
222353901Smckusick printf("sd%d: bad target status 0x%x\n",
222453901Smckusick unit, sc->sc_tstatus);
222553901Smckusick goto sdintr_error;
222653901Smckusick }
222753901Smckusick break;
222853901Smckusick
222953901Smckusick /****************************************/
223053901Smckusick /* */
223153901Smckusick /* REQUEST SENSE analysis */
223253901Smckusick /* */
223353901Smckusick /****************************************/
223453901Smckusick case SDCS_RSENSE:
223553901Smckusick case SDCS_PREVRMB|SDCS_RSENSE:
223653901Smckusick case SDCS_ECC|SDCS_RASREAD|SDCS_RSENSE:
223753901Smckusick case SDCS_ECC|SDCS_RASWRITE|SDCS_RSENSE:
223853901Smckusick case SDCS_ECCOFF|SDCS_RSENSE:
223953901Smckusick case SDCS_ECCOFF|SDCS_RASBLK|SDCS_RSENSE:
224053901Smckusick case SDCS_ECCOFF|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE:
224153901Smckusick case SDCS_ECC|SDCS_RASBLK|SDCS_RSENSE:
224253901Smckusick case SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE:
224353901Smckusick if (tstatus != TGST_GOOD) {
224453901Smckusick printf("sd%d: bad target status 0x%x\n",
224553901Smckusick unit, sc->sc_tstatus);
224653901Smckusick goto sdintr_error;
224753901Smckusick }
224853901Smckusick /*
224953901Smckusick * error message print out
225053901Smckusick */
225153901Smckusick code = sderrordisp(sce, ii);
225253901Smckusick
225353901Smckusick
225453901Smckusick if ((sdc->sdc_state == (SDCS_ECC|SDCS_RASBLK|SDCS_RSENSE)) ||
225553901Smckusick (sdc->sdc_state == (SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE))) {
225653901Smckusick printf("sd%d: cannot reassign block %d\n",
225753901Smckusick unit, sdd->sdd_badsect);
225853901Smckusick goto sdintr_error;
225953901Smckusick }
226053901Smckusick if (sdc->sdc_state == (SDCS_PREVRMB|SDCS_RSENSE)) {
226153901Smckusick if (sce->sce_skey == 0x2) {
226253901Smckusick /*
226353901Smckusick * Not ready
226453901Smckusick */
226553901Smckusick sdc->sdc_state = SDCS_PREVRMB;
226653901Smckusick timeout(delay_medrmv, (caddr_t)ii, hz);
226753901Smckusick return;
226853901Smckusick }
226953901Smckusick }
227053901Smckusick
227153901Smckusick /* */
227253901Smckusick /* RSENSE error handler */
227353901Smckusick /* */
227453901Smckusick switch (code) {
227553901Smckusick
227653901Smckusick /********************************/
227753901Smckusick /* continue */
227853901Smckusick /********************************/
227953901Smckusick /* NO SENSE */
228053901Smckusick case 0x00: /* No Additional Sense Information */
228153901Smckusick /* RECOVERED ERROR */
228253901Smckusick case 0x38: /* Recovered with Auto-Reallocation */
228353901Smckusick sdc->sdc_state &= ~SDCS_RSENSE;
228453901Smckusick goto check_target_status;
228553901Smckusick
228653901Smckusick /********************************/
228753901Smckusick /* continue or error */
228853901Smckusick /********************************/
228953901Smckusick /* ILLEGAL REQUEST */
229053901Smckusick
229153901Smckusick case 0x21: /* illegal Logical Block Address */
229253901Smckusick if (&st->sizes[dev2part(bp->b_dev)] == NULL)
229353901Smckusick goto sdintr_error;
229453901Smckusick if (bp->b_bcount > 0) {
229553901Smckusick bp->b_resid = bp->b_bcount
229653901Smckusick - (sdd->sdd_badsect * sdd->sdd_sectsize
229753901Smckusick - (st->sizes[dev2part(bp->b_dev)].sd_blkoff
229853901Smckusick + dkblock(bp)) * DEV_BSIZE);
229953901Smckusick }
230053901Smckusick if (bp->b_resid >= bp->b_bcount || bp->b_resid <= 0) {
230153901Smckusick /*
230253901Smckusick * all I/O failure
230353901Smckusick */
230453901Smckusick bp->b_resid = bp->b_bcount;
230553901Smckusick goto sdintr_error;
230653901Smckusick }
230753901Smckusick /* Ignore error */
230853901Smckusick break;
230953901Smckusick
231053901Smckusick /* MEDIUM ERROR */
231153901Smckusick case 0x31: /* Medium Format Corrupted */
231253901Smckusick sdd->sdd_flags |= SDDF_NONFMT;
231353901Smckusick /* Ignore error */
231453901Smckusick break;
231553901Smckusick
231653901Smckusick /********************************/
231753901Smckusick /* more retry */
231853901Smckusick /********************************/
231953901Smckusick /* MEDIUM or RECOVERED ERROR */
232053901Smckusick case 0x10: /* ID CRC Error */
232153901Smckusick case 0x12: /* No Address Mark found in ID field */
232253901Smckusick case 0x13: /* No Address Mark found in Data field */
232353901Smckusick case 0x14: /* No recode found */
232453901Smckusick /* H/W or MEDIUM or RECOVERED ERROR */
232553901Smckusick case 0x15: /* Seek Positioning Error */
232653901Smckusick if (sd_ignore_error) {
232753901Smckusick sdc->sdc_state = SDCS_NORMAL;
232853901Smckusick goto check_target_status;
232953901Smckusick }
233053901Smckusick /* fall through */
233153901Smckusick
233253901Smckusick /* H/W ERROR */
233353901Smckusick case 0x01: /* No Index/Address Mark Found signal */
233453901Smckusick case 0x02: /* No Seek Complete */
233553901Smckusick case 0x06: /* No Track Zero found */
233653901Smckusick /* H/W ERROR or RECOVERED ERROR */
233753901Smckusick case 0x03: /* Write Fault */
233853901Smckusick case 0x08: /* Logical Unit Communication Failure */
233953901Smckusick case 0x09: /* Track Following Error */
234053901Smckusick case 0x0b: /* Load/Unload Failure */
234153901Smckusick case 0x0c: /* Spindle Failure */
234253901Smckusick case 0x0d: /* Focus Failure */
234353901Smckusick case 0x0e: /* Tracking Failure */
234453901Smckusick case 0x0f: /* Drive Initialization Failure */
234553901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD|SDCS_REZERO;
234653901Smckusick
234753901Smckusick scinit(sc, slave, sdd->sdd_sectsize);
234853901Smckusick /* sc_cdb */
234953901Smckusick sc->sc_opcode = SCOP_REZERO;
235053901Smckusick
235153901Smckusick sddgo(im);
235253901Smckusick return;
235353901Smckusick
235453901Smckusick /********************************/
235553901Smckusick /* re-allocate & retry */
235653901Smckusick /********************************/
235753901Smckusick /* MEDIUM or RECOVERED ERROR */
235853901Smckusick case 0x11: /* Unrecovered Read Error */
235953901Smckusick if (sdc->sdc_state & SDCS_RASREAD) {
236053901Smckusick sdintr_lostdata:
236153901Smckusick sdc->sdc_state =
236253901Smckusick SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA;
236353901Smckusick im->im_tab.b_active = 2;
236453901Smckusick scop_rasblk(intr, sc, slave,
236553901Smckusick SCSI_INTEN, sdd->sdd_badsect);
236653901Smckusick sdd->sdd_flags &= ~SDDF_VBADSECT;
236753901Smckusick return;
236853901Smckusick }
236953901Smckusick /* fall through */
237053901Smckusick
237153901Smckusick /* RECOVERED ERROR */
237253901Smckusick case 0x17: /* Recovered read data with retries */
237353901Smckusick case 0x18: /* Recovered read data with ECC */
237453901Smckusick /*
237553901Smckusick * set ECC ON & more retry
237653901Smckusick */
237753901Smckusick if (sdc->sdc_firmware & SDCFW_DEFMODE)
237853901Smckusick goto sdintr_ecc;
237953901Smckusick
238053901Smckusick if (sdc->sdc_state & SDCS_RASREAD)
238153901Smckusick goto sdintr_rasblk;
238253901Smckusick
238353901Smckusick sdc->sdc_state = SDCS_ECC;
238453901Smckusick goto sdintr_msel_set;
238553901Smckusick
238653901Smckusick /********************************/
238753901Smckusick /* unit start & retry */
238853901Smckusick /********************************/
238953901Smckusick /* NOT READY */
239053901Smckusick case 0x04: /* Drive Not Ready */
239153901Smckusick if (sdc->sdc_state & SDCS_ECC)
239253901Smckusick sdc->sdc_state = SDCS_ECCOFF|SDCS_RETRY;
239353901Smckusick else
239453901Smckusick sdc->sdc_state = SDCS_RETRY;
239553901Smckusick goto sdintr_stst;
239653901Smckusick
239753901Smckusick /********************************/
239853901Smckusick /* retry */
239953901Smckusick /********************************/
240053901Smckusick /* UNIT ATTENTION */
240153901Smckusick case 0x28: /* Medium Changed */
240253901Smckusick sdd->sdd_flags &= ~(SDDF_NONFMT
240353901Smckusick |SDDF_SAMEDSK
240453901Smckusick |SDDF_REQ_EJECT
240553901Smckusick |SDDF_XUSE
240653901Smckusick |SDDF_INHRMV
240753901Smckusick |SDDF_ERASEOFF);
240853901Smckusick /* fall through */
240953901Smckusick
241053901Smckusick case 0x29: /* Power On or Reset or Bus Device Reset */
241153901Smckusick if (sdc->sdc_firmware & SDCFW_RMB) {
241253901Smckusick /***************************/
241353901Smckusick /* medium removable device */
241453901Smckusick /***************************/
241553901Smckusick sdc->sdc_state = SDCS_PREVRMB;
241653901Smckusick im->im_tab.b_active = 2;
241753901Smckusick scop_medrmv(intr, sc, slave,
241853901Smckusick SCSI_INTEN, SDRMV_PREV);
241953901Smckusick return;
242053901Smckusick }
242153901Smckusick
242253901Smckusick case 0x2a: /* Mode Select Parameter Changed */
242353901Smckusick case 0x47: /* SCSI interface bus parity error */
242453901Smckusick if (sdc->sdc_state & SDCS_ECC) {
242553901Smckusick sdc->sdc_state = SDCS_RETRY;
242653901Smckusick goto sdintr_msel_reset;
242753901Smckusick }
242853901Smckusick sdc->sdc_state = SDCS_NORMAL;
242953901Smckusick goto sdintr_exec;
243053901Smckusick
243153901Smckusick /********************************/
243253901Smckusick /* set error flag */
243353901Smckusick /********************************/
243453901Smckusick case 0x40: /* RAM failure */
243553901Smckusick case 0x41: /* Data Path diagnostic failure */
243653901Smckusick case 0x42: /* Power On diagnostic failure */
243753901Smckusick
243853901Smckusick case 0xb2: /* Caddy load/eject failed */
243953901Smckusick case 0xb4: /* Focus servo failure */
244053901Smckusick case 0xb5: /* Spindle servo failure */
244153901Smckusick case 0xb6: /* Caddy load mechanism failed */
244253901Smckusick goto sdintr_error;
244353901Smckusick
244453901Smckusick /*MO*/ case 0x80: /* Limit Laser Life */
244553901Smckusick /*MO*/ case 0x81: /* Focus Coil Over-current Failure */
244653901Smckusick /*MO*/ case 0x82: /* Tracking Coil Over-current Failure */
244753901Smckusick /*MO*/ case 0x83: /* Temperature Alarm */
244853901Smckusick /*CD*/ /* case 0x80: */ /* Prevent bit is set */
244953901Smckusick /*CD*/ /* case 0x81: */ /* Logical unit is reserved */
245053901Smckusick /*CD*/ /* case 0x82: */ /* End of usr area encountered */
245153901Smckusick /*CD*/ /* case 0x83: */ /* Overlapped commands attempted */
245253901Smckusick goto sdintr_error;
245353901Smckusick
245453901Smckusick default:
245553901Smckusick /*
245653901Smckusick * error detect, but what shall we do ?
245753901Smckusick */
245853901Smckusick /* case 0x05: */ /* Drive Not Selected */
245953901Smckusick /* case 0x07: */ /* Multiple Drives Selected */
246053901Smckusick /* case 0x0a: */ /* No disk */
246153901Smckusick /* case 0x1a: */ /* Parameter overrun */
246253901Smckusick /* case 0x1b: */ /* Synchronous transfer error */
246353901Smckusick /* case 0x1d: */ /* Compare error */
246453901Smckusick /* case 0x22: */ /* Illegal function for device type */
246553901Smckusick /* case 0x23: */ /* Illegal function for Medium type */
246653901Smckusick /* case 0x25: */ /* Illegal LUN */
246753901Smckusick /* case 0x27: */ /* Write Protected */
246853901Smckusick /* case 0x2b: */ /* Firmware has been downloaded */
246953901Smckusick /* case 0x39: */ /* Automatic Reallocation Failure */
247053901Smckusick /* case 0x43: */ /* Message Reject Error */
247153901Smckusick /* case 0x45: */ /* Selection/Reselection failure */
247253901Smckusick /* case 0x48: */ /* Initiator detected error */
247353901Smckusick /* case 0x49: */ /* Inappropriate/illegal message */
247453901Smckusick /* case 0x60: */ /* COPY: STATUS error */
247553901Smckusick /* case 0x85: */ /* Audio address not valid */
247653901Smckusick /* case 0xb0: */ /* Caddy not inserted in drive */
247753901Smckusick /* case 0xb1: */ /* Unable to recover TOC */
247853901Smckusick /* case 0xb3: */ /* CIRC unrecovered data error(L-EC off) */
247953901Smckusick /* case 0xc3: */ /* COPY: Illegale CDB length */
248053901Smckusick /* case 0xc5: */ /* COPY: Catastrophic error */
248153901Smckusick /* case 0xc6: */ /* COPY: Illegal phase change */
248253901Smckusick /* case 0xfc: */ /* COPY: MODE SENSE failed */
248353901Smckusick
248453901Smckusick /*
248553901Smckusick * medium error
248653901Smckusick */
248753901Smckusick /* case 0x19: */ /* Defect list error */
248853901Smckusick /* case 0x1c: */ /* Primary Defect List not found */
248953901Smckusick /* case 0x30: */ /* Incompatible Cartridge */
249053901Smckusick /* case 0x32: */ /* No Spare Defect Location Available */
249153901Smckusick /* case 0x3a: */ /* Defect List Update Failure */
249253901Smckusick /* case 0x3d: */ /* Defect List Not Available */
249353901Smckusick goto sdintr_error;
249453901Smckusick }
249553901Smckusick /*
249653901Smckusick * No error detected or ignored.
249753901Smckusick */
249853901Smckusick break;
249953901Smckusick
250053901Smckusick /************************************************/
250153901Smckusick /* */
250253901Smckusick /* PREVENT MEDIUM REMOVABLE COMMAND */
250353901Smckusick /* */
250453901Smckusick /************************************************/
250553901Smckusick case SDCS_PREVRMB:
250653901Smckusick if (tstatus == TGST_CC) {
250753901Smckusick sdc->sdc_state = SDCS_PREVRMB|SDCS_RSENSE;
250853901Smckusick goto sdintr_rsense;
250953901Smckusick }
251053901Smckusick sdd->sdd_flags |= SDDF_INHRMV;
251153901Smckusick if (sdc->sdc_state & SDCS_ECC) {
251253901Smckusick sdc->sdc_state = SDCS_RETRY;
251353901Smckusick goto sdintr_msel_reset;
251453901Smckusick }
251553901Smckusick sdc->sdc_state = SDCS_NORMAL;
251653901Smckusick goto sdintr_exec;
251753901Smckusick break;
251853901Smckusick
251953901Smckusick /****************************************/
252053901Smckusick /* */
252153901Smckusick /* REZERO done & RETRY COMMAND */
252253901Smckusick /* */
252353901Smckusick /****************************************/
252453901Smckusick case SDCS_ECC|SDCS_ECC_HOLD|SDCS_REZERO:
252553901Smckusick if (sdc->sdc_firmware & SDCFW_DEFMODE) {
252653901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD|SDCS_RETRY;
252753901Smckusick goto sdintr_stst;
252853901Smckusick }
252953901Smckusick
253053901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD;
253153901Smckusick goto sdintr_msel_set;
253253901Smckusick
253353901Smckusick /********************************/
253453901Smckusick /* */
253553901Smckusick /* RETRY COMMAND */
253653901Smckusick /* */
253753901Smckusick /********************************/
253853901Smckusick case SDCS_RETRY:
253953901Smckusick sdc->sdc_state = SDCS_NORMAL;
254053901Smckusick goto sdintr_exec;
254153901Smckusick
254253901Smckusick /************************************************/
254353901Smckusick /* */
254453901Smckusick /* ERROR CORRECTION ON MODE SELECT result */
254553901Smckusick /* */
254653901Smckusick /************************************************/
254753901Smckusick case SDCS_ECC:
254853901Smckusick if (tstatus != TGST_GOOD) {
254953901Smckusick printf("sd%d: bad target status 0x%x\n",
255053901Smckusick unit, sc->sc_tstatus);
255153901Smckusick goto sdintr_error;
255253901Smckusick }
255353901Smckusick sdintr_ecc:
255453901Smckusick if (bp->b_flags & B_READ) {
255553901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_RASREAD;
255653901Smckusick im->im_tab.b_active = 2;
255753901Smckusick scop_rdwr(intr, sc, slave, SCSI_INTEN,
255853901Smckusick B_READ, sdwork,
255953901Smckusick sdd->sdd_badsect, sdd->sdd_sectsize);
256053901Smckusick return;
256153901Smckusick }
256253901Smckusick goto sdintr_rasblk;
256353901Smckusick
256453901Smckusick /************************************************/
256553901Smckusick /* */
256653901Smckusick /* READ DATA from BAD BLOCK result */
256753901Smckusick /* */
256853901Smckusick /************************************************/
256953901Smckusick case SDCS_ECC|SDCS_RASREAD:
257053901Smckusick if (tstatus == TGST_CC) {
257153901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_RASREAD|SDCS_RSENSE;
257253901Smckusick goto sdintr_rsense;
257353901Smckusick } else if (tstatus != TGST_GOOD) {
257453901Smckusick printf("sd%d: bad target status 0x%x\n",
257553901Smckusick unit, sc->sc_tstatus);
257653901Smckusick printf("sd%d: cannot read block\n", unit);
257753901Smckusick goto sdintr_error;
257853901Smckusick }
257953901Smckusick sdintr_rasblk:
258053901Smckusick if (sdd->sdd_flags & SDDF_WPROTECT)
258153901Smckusick goto sdintr_error;
258253901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_RASBLK;
258353901Smckusick im->im_tab.b_active = 2;
258453901Smckusick scop_rasblk(intr, sc, slave, SCSI_INTEN, sdd->sdd_badsect);
258553901Smckusick sdd->sdd_flags &= ~SDDF_VBADSECT;
258653901Smckusick return;
258753901Smckusick
258853901Smckusick /****************************************/
258953901Smckusick /* */
259053901Smckusick /* REASSIGN BLOCK result */
259153901Smckusick /* */
259253901Smckusick /****************************************/
259353901Smckusick case SDCS_ECC|SDCS_RASBLK:
259453901Smckusick if (tstatus == TGST_CC) {
259553901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_RASBLK|SDCS_RSENSE;
259653901Smckusick goto sdintr_rsense;
259753901Smckusick } else if (tstatus != TGST_GOOD) {
259853901Smckusick printf("sd%d: bad target status 0x%x\n",
259953901Smckusick unit, sc->sc_tstatus);
260053901Smckusick goto sdintr_error;
260153901Smckusick }
260253901Smckusick printf("sd%d: block %d is reassigned\n",
260353901Smckusick unit, sdd->sdd_badsect);
260453901Smckusick if (bp->b_flags & B_READ) {
260553901Smckusick sdintr_raswrite:
260653901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_RASWRITE;
260753901Smckusick im->im_tab.b_active = 2;
260853901Smckusick scop_rdwr(intr, sc, slave, SCSI_INTEN,
260953901Smckusick B_WRITE, sdwork,
261053901Smckusick sdd->sdd_badsect, sdd->sdd_sectsize);
261153901Smckusick return;
261253901Smckusick }
261353901Smckusick sdc->sdc_state = SDCS_RETRY;
261453901Smckusick goto sdintr_msel_reset;
261553901Smckusick
261653901Smckusick /************************************************/
261753901Smckusick /* */
261853901Smckusick /* WRITE DATA to REASSIGNED BLOCK result */
261953901Smckusick /* */
262053901Smckusick /************************************************/
262153901Smckusick case SDCS_ECC|SDCS_RASWRITE:
262253901Smckusick if (tstatus == TGST_CC) {
262353901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_RASWRITE|SDCS_RSENSE;
262453901Smckusick goto sdintr_rsense;
262553901Smckusick } else if (tstatus != TGST_GOOD) {
262653901Smckusick printf("sd%d: bad target status 0x%x\n",
262753901Smckusick unit, sc->sc_tstatus);
262853901Smckusick goto sdintr_error;
262953901Smckusick }
263053901Smckusick sdc->sdc_state = SDCS_RETRY;
263153901Smckusick goto sdintr_msel_reset;
263253901Smckusick
263353901Smckusick /****************************************/
263453901Smckusick /* */
263553901Smckusick /* reset ECC & RETRY TIMES */
263653901Smckusick /* */
263753901Smckusick /****************************************/
263853901Smckusick case SDCS_ECCOFF|SDCS_RETRY:
263953901Smckusick sdc->sdc_state = SDCS_RETRY;
264053901Smckusick goto sdintr_msel_reset;
264153901Smckusick
264253901Smckusick /********************************************************/
264353901Smckusick /* */
264453901Smckusick /* READ DATA from BAD BLOCK result in faliure */
264553901Smckusick /* */
264653901Smckusick /********************************************************/
264753901Smckusick case SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA:
264853901Smckusick if (tstatus == TGST_CC) {
264953901Smckusick sdc->sdc_state =
265053901Smckusick SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE;
265153901Smckusick goto sdintr_rsense;
265253901Smckusick } else if (tstatus != TGST_GOOD) {
265353901Smckusick printf("sd%d: rasblk: bad target status 0x%x\n",
265453901Smckusick unit, sc->sc_tstatus);
265553901Smckusick goto sdintr_error;
265653901Smckusick }
265753901Smckusick bzero(sdwork, sdd->sdd_sectsize);
265853901Smckusick scop_rdwr(intr, sc, slave, SCSI_INTDIS,
265953901Smckusick B_WRITE, sdwork, sdd->sdd_badsect, sdd->sdd_sectsize);
266053901Smckusick printf("sd%d: block %d is reassigned (lost data)\n",
266153901Smckusick unit, sdd->sdd_badsect);
266253901Smckusick goto sdintr_error;
266353901Smckusick
266453901Smckusick /****************************************/
266553901Smckusick /* */
266653901Smckusick /* issue START UNIT command */
266753901Smckusick /* */
266853901Smckusick /****************************************/
266953901Smckusick case SDCS_ECC|SDCS_ECC_HOLD:
267053901Smckusick /*
267153901Smckusick * Drive not ready... so start..
267253901Smckusick */
267353901Smckusick sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD|SDCS_RETRY;
267453901Smckusick sdintr_stst:
267553901Smckusick timeout(delay_start, (caddr_t)ii, hz);
267653901Smckusick return;
267753901Smckusick
267853901Smckusick /****************************************/
267953901Smckusick /* */
268053901Smckusick /* RETRY with ECC & more RETRYS */
268153901Smckusick /* */
268253901Smckusick /****************************************/
268353901Smckusick case SDCS_ECC|SDCS_ECC_HOLD|SDCS_RETRY:
268453901Smckusick sdc->sdc_state = SDCS_ECCOFF;
268553901Smckusick sdintr_exec:
268653901Smckusick if (sdc->sdc_countcc++ > MAXRETRYCNT)
268753901Smckusick goto sdintr_error;
268853901Smckusick sdexec(bp);
268953901Smckusick return;
269053901Smckusick
269153901Smckusick /****************************************/
269253901Smckusick /* */
269353901Smckusick /* reset ECC & RETRY TIMES */
269453901Smckusick /* */
269553901Smckusick /****************************************/
269653901Smckusick case SDCS_ECCOFF:
269753901Smckusick if (tstatus == TGST_CC) {
269853901Smckusick sdc->sdc_state = SDCS_ECCOFF|SDCS_RSENSE;
269953901Smckusick goto sdintr_rsense;
270053901Smckusick } else if (tstatus != TGST_GOOD) {
270153901Smckusick printf("sd%d: bad target status 0x%x\n",
270253901Smckusick unit, sc->sc_tstatus);
270353901Smckusick goto sdintr_error;
270453901Smckusick }
270553901Smckusick sdc->sdc_state = SDCS_NORMAL;
270653901Smckusick goto sdintr_msel_reset;
270753901Smckusick
270853901Smckusick sdintr_msel_set:
270953901Smckusick /*
271053901Smckusick * set more ERROR RECOVERY PARAMETERS
271153901Smckusick */
271253901Smckusick if ((erp_page = sdi->max_ERP_page) == NULL)
271353901Smckusick goto check_target_status;
271453901Smckusick bzero((caddr_t)sc->sc_param, 4);
271553901Smckusick len = *(erp_page + 1) + 2;
271653901Smckusick bcopy(erp_page, &sc->sc_param[4], len);
271753901Smckusick
271853901Smckusick im->im_tab.b_active = 2;
271953901Smckusick scop_mselect(intr, sc, slave, SCSI_INTEN,
272053901Smckusick (SDM_PF<<24) + len +4, (caddr_t)0);
272153901Smckusick return;
272253901Smckusick
272353901Smckusick sdintr_msel_reset:
272453901Smckusick if (sdc->sdc_firmware & SDCFW_DEFMODE)
272553901Smckusick goto sdintr_exec;
272653901Smckusick
272753901Smckusick /*
272853901Smckusick * set normal ERROR RECOVERY PARAMETERS
272953901Smckusick */
273053901Smckusick erp_page = sdi->ERP_page;
273153901Smckusick bzero((caddr_t)sc->sc_param, 4);
273253901Smckusick len = *(erp_page + 1) + 2;
273353901Smckusick bcopy(erp_page, &sc->sc_param[4], len);
273453901Smckusick
273553901Smckusick im->im_tab.b_active = 2;
273653901Smckusick scop_mselect(intr, sc, slave, SCSI_INTEN,
273753901Smckusick (SDM_PF<<24) + len +4, (caddr_t)0);
273853901Smckusick return;
273953901Smckusick
274053901Smckusick sdintr_error:
274153901Smckusick bp->b_flags |= B_ERROR;
274253901Smckusick if (sdc->sdc_state & SDCS_ECC) {
274353901Smckusick sdc->sdc_state = SDCS_NORMAL;
274453901Smckusick goto sdintr_msel_reset;
274553901Smckusick }
274653901Smckusick break;
274753901Smckusick
274853901Smckusick /*
274953901Smckusick * UNKNOWN STATUS
275053901Smckusick */
275153901Smckusick default:
275253901Smckusick printf("sd%d: unknown status (0x%x)\n", unit, sdc->sdc_state);
275353901Smckusick goto sdintr_error;
275453901Smckusick }
275553901Smckusick
275653901Smckusick sdintr_done:
275753901Smckusick
275853901Smckusick if (bp->b_flags & B_ERROR) {
275953901Smckusick printf("%s%d%c: hard error sn%d ", "sd",
276053901Smckusick minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
276153901Smckusick printf("\n");
276253901Smckusick }
276353901Smckusick sdd->sdd_lastblk = dkblock(bp) + btodb(bp->b_bcount - bp->b_resid);
276453901Smckusick sdc->sdc_countcc = 0;
276553901Smckusick sdc->sdc_retrycnt = 0;
276653901Smckusick sdd->sdd_flags &= ~SDDF_VBADSECT;
276753901Smckusick
276853901Smckusick if (im->im_tab.b_active) {
276953901Smckusick im->im_tab.b_active = 0;
277053901Smckusick im->im_tab.b_errcnt = 0;
277157612Sutashiro im->im_tab.b_actf = 0;
277253901Smckusick dp->b_active = 0;
277353901Smckusick dp->b_errcnt = 0;
277457612Sutashiro dp->b_actf = bp->b_actf;
277553901Smckusick if (bp == &csdbuf[unit]) {
277653901Smckusick register struct scsi *ksc = &kernscsi[unit];
277753901Smckusick /* copy result */
277853901Smckusick bcopy((caddr_t)sc, (caddr_t)ksc, sizeof(struct scsi));
277953901Smckusick }
278053901Smckusick
278153901Smckusick iodone(bp);
278253901Smckusick
278353901Smckusick /*
278453901Smckusick * If this unit has more work to do,
278553901Smckusick * then start it up right away.
278653901Smckusick */
278753901Smckusick if (dp->b_actf)
278853901Smckusick sdustart(ii);
278953901Smckusick }
279053901Smckusick as &= ~(1 << slave);
279153901Smckusick
279253901Smckusick sdc->sdc_state = SDCS_NORMAL;
279353901Smckusick
279453901Smckusick /*
279553901Smckusick * UNLOCK SCSI access
279653901Smckusick */
279753901Smckusick sdc->sdc_firmware &= ~SDCFW_BUSY;
279853901Smckusick
279953901Smckusick start:
280053901Smckusick /*
280153901Smckusick * Process other units which need attention.
280253901Smckusick * For each unit which needs attention, call
280353901Smckusick * the unit start routine to place the slave
280453901Smckusick * on the controller device queue.
280553901Smckusick */
280653901Smckusick sdc->sdc_softas = 0;
280753901Smckusick while (unit = ffs(as)) {
280853901Smckusick unit--;
280953901Smckusick as &= ~(1 << unit);
281053901Smckusick sdustart(sdip[im->im_ctlr][unit]);
281153901Smckusick }
281253901Smckusick /*
281353901Smckusick * If the controller is not transferring,
281453901Smckusick * but there are devices ready to transfer,
281553901Smckusick * start the controller.
281653901Smckusick */
281753901Smckusick if (im->im_tab.b_actf && im->im_tab.b_active == 0)
281853901Smckusick (void) sdstart(im);
281953901Smckusick }
282053901Smckusick
wait_re_init_done(bp)282153901Smckusick wait_re_init_done(bp)
282253901Smckusick register struct buf *bp;
282353901Smckusick {
282453901Smckusick if (re_init_done >= 2)
282553901Smckusick sdexec(bp);
282653901Smckusick else
282753901Smckusick timeout(wait_re_init_done, bp, 10*hz);
282853901Smckusick }
282953901Smckusick
283053901Smckusick delay_start(ii)
283153901Smckusick struct iop/**/_device *ii;
283253901Smckusick {
283353901Smckusick ii->ii_mi->im_tab.b_active = 2;
283453901Smckusick scop_stst(ii->ii_intr, get_scsi(ii->ii_intr), ii->ii_slave,
283553901Smckusick SCSI_INTEN, SDSS_START);
283653901Smckusick }
283753901Smckusick
283853901Smckusick delay_medrmv(ii)
283953901Smckusick struct iop/**/_device *ii;
284053901Smckusick {
284153901Smckusick ii->ii_mi->im_tab.b_active = 2;
284253901Smckusick scop_medrmv(ii->ii_intr, get_scsi(ii->ii_intr), ii->ii_slave,
284353901Smckusick SCSI_INTEN, SDRMV_PREV);
284453901Smckusick }
284553901Smckusick
sderrordisp(rsen_data,ii)284653901Smckusick sderrordisp(rsen_data, ii)
284753901Smckusick u_char *rsen_data;
284853901Smckusick struct iop/**/_device *ii;
284953901Smckusick {
285053901Smckusick register struct sc_extnd *sce;
285153901Smckusick register struct sdc_softc *sdc;
285253901Smckusick register struct sdd_softc *sdd;
285353901Smckusick register int unit;
285453901Smckusick register int code;
285553901Smckusick struct sc_nextnd *scn;
285653901Smckusick struct msg_list *ml;
285753901Smckusick
285853901Smckusick unit = ii->ii_unit;
285953901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
286053901Smckusick sdd = &sdd_softc[unit];
286153901Smckusick
286253901Smckusick sce = (struct sc_extnd *)rsen_data;
286353901Smckusick
286453901Smckusick if (sce->sce_extend == 0x70) {
286553901Smckusick /*
286653901Smckusick * Extended Sense data
286753901Smckusick */
286853901Smckusick code = sce->sce_sdecode;
286953901Smckusick
287053901Smckusick if (code & 0x80)
287153901Smckusick ml = ecodelist_mo;
287253901Smckusick else
287353901Smckusick ml = ecodelist;
287453901Smckusick
287553901Smckusick if (sce->sce_advalid) {
287653901Smckusick if ((sdd->sdd_flags & SDDF_VBADSECT) == 0) {
287753901Smckusick #ifdef mips
287853901Smckusick sdd->sdd_badsect = (sce->sce_infob1 << 24) +
287953901Smckusick (sce->sce_infob2 << 16) +
288053901Smckusick (sce->sce_infob3 << 8) +
288153901Smckusick (sce->sce_infob4);
288253901Smckusick #else
288353901Smckusick sdd->sdd_badsect = *((int *)&sce->sce_infob1);
288453901Smckusick #endif
288553901Smckusick sdd->sdd_flags |= SDDF_VBADSECT;
288653901Smckusick }
288753901Smckusick }
288853901Smckusick
288953901Smckusick if (!rsense_msg_disp && !isdispmsg(code, ml, sdc->sdc_countcc))
289053901Smckusick return (code);
289153901Smckusick
289253901Smckusick if (sce->sce_advalid) {
289353901Smckusick int sn;
289453901Smckusick #ifdef mips
289553901Smckusick sn = (sce->sce_infob1 << 24) +
289653901Smckusick (sce->sce_infob2 << 16) +
289753901Smckusick (sce->sce_infob3 << 8) +
289853901Smckusick (sce->sce_infob4);
289953901Smckusick #else
290053901Smckusick sn = *((int *)&sce->sce_infob1);
290153901Smckusick #endif
290253901Smckusick if (sce->sce_addlen >= 5) {
290353901Smckusick printf("sd%d(sn %d): skey=0x%x, code=0x%x\n",
290453901Smckusick unit, sn, sce->sce_skey, code);
290553901Smckusick } else {
290653901Smckusick printf("sd%d(sn %d): skey=0x%x\n",
290753901Smckusick unit, sn, sce->sce_skey);
290853901Smckusick }
290953901Smckusick } else {
291053901Smckusick if (sce->sce_addlen >= 5)
291153901Smckusick printf("sd%d: skey=0x%x, code=0x%x\n",
291253901Smckusick unit, sce->sce_skey, code);
291353901Smckusick else
291453901Smckusick printf("sd%d: skey=0x%x\n",
291553901Smckusick unit, sce->sce_skey);
291653901Smckusick }
291753901Smckusick if (sce->sce_addlen >= 6)
291853901Smckusick printf("sd%d: ASCQ=0x%x\n", unit, sce->sce_ascq);
291953901Smckusick {
292053901Smckusick u_char *p;
292153901Smckusick int len;
292253901Smckusick
292353901Smckusick len = 8 + sce->sce_addlen;
292453901Smckusick if (len > RSEN_CNT)
292553901Smckusick len = RSEN_CNT;
292653901Smckusick p = (u_char *)sce;
292753901Smckusick printf("sd%d: ", unit);
292853901Smckusick while (len--)
292953901Smckusick printf("%x ", *p++);
293053901Smckusick printf("\n");
293153901Smckusick }
293253901Smckusick } else {
293353901Smckusick /*
293453901Smckusick * Non-extended Sense data
293553901Smckusick */
293653901Smckusick scn = (struct sc_nextnd *)rsen_data;
293753901Smckusick
293853901Smckusick code = scn->scn_ecode;
293953901Smckusick ml = ecodelist;
294053901Smckusick if (sce->sce_advalid) {
294153901Smckusick if ((sdd->sdd_flags & SDDF_VBADSECT) == 0) {
294253901Smckusick sdd->sdd_badsect = scn->scn_secno;
294353901Smckusick sdd->sdd_flags |= SDDF_VBADSECT;
294453901Smckusick }
294553901Smckusick }
294653901Smckusick if (rsense_msg_disp || isdispmsg(code, ml, sdc->sdc_countcc)) {
294753901Smckusick if (sce->sce_advalid)
294853901Smckusick printf("sd%d(sn %d): code=0x%x\n",
294953901Smckusick unit, scn->scn_secno, code);
295053901Smckusick else
295153901Smckusick printf("sd%d: code=0x%x\n", unit, code);
295253901Smckusick }
295353901Smckusick }
295453901Smckusick return (code);
295553901Smckusick }
295653901Smckusick
295753901Smckusick void
sdminphys(bp)295853901Smckusick sdminphys(bp)
295953901Smckusick struct buf *bp;
296053901Smckusick {
296153901Smckusick if (bp->b_bcount > MAXSDPHYS)
296253901Smckusick bp->b_bcount = MAXSDPHYS;
296353901Smckusick }
296453901Smckusick
296553901Smckusick
296653901Smckusick #define sdphysio physio
296753901Smckusick
sdread(dev,uio,flag)296853901Smckusick sdread(dev, uio, flag)
296953901Smckusick register dev_t dev;
297053901Smckusick struct uio *uio;
297153901Smckusick int flag;
297253901Smckusick {
297353901Smckusick register struct iop/**/_device *ii;
297453901Smckusick register int unit;
297553901Smckusick
297653901Smckusick unit = dev2unit(dev);
297753901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0)
297853901Smckusick return (ENXIO);
297953901Smckusick
298053901Smckusick return (sdphysio(sdstrategy, &rsdbuf[unit], dev, B_READ, sdminphys, uio));
298153901Smckusick }
298253901Smckusick
sdwrite(dev,uio,flag)298353901Smckusick sdwrite(dev, uio, flag)
298453901Smckusick register dev_t dev;
298553901Smckusick struct uio *uio;
298653901Smckusick int flag;
298753901Smckusick {
298853901Smckusick register struct iop/**/_device *ii;
298953901Smckusick register int unit;
299053901Smckusick
299153901Smckusick unit = dev2unit(dev);
299253901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0)
299353901Smckusick return (ENXIO);
299453901Smckusick
299553901Smckusick return (sdphysio(sdstrategy, &rsdbuf[unit], dev, B_WRITE, sdminphys, uio));
299653901Smckusick }
299753901Smckusick
299853901Smckusick #define MAXBL 256
299953901Smckusick
300058620Sutashiro struct Partinfo {
300158620Sutashiro /*00*/ daddr_t dp_nblocks; /* partition size (sector #) */
300258620Sutashiro /*04*/ daddr_t dp_blkoff; /* partition start block */
300358620Sutashiro /*08*/
300458620Sutashiro };
300558620Sutashiro
300658620Sutashiro struct dkst {
300758620Sutashiro /*00*/ int dks_ncyl; /* # cylinders / drive */
300858620Sutashiro /*04*/ int dks_ntrak; /* # tracks / cylinder */
300958620Sutashiro /*08*/ int dks_nsect; /* # sectors / track */
301058620Sutashiro /*0c*/ int dks_rps; /* # revolutions / second */
301158620Sutashiro /*10*/
301258620Sutashiro };
301358620Sutashiro
301453901Smckusick /*ARGSUSED*/
sdioctl(dev,cmd,data,flag)301553901Smckusick sdioctl(dev, cmd, data, flag)
301653901Smckusick dev_t dev;
301753901Smckusick int cmd;
301853901Smckusick caddr_t data;
301953901Smckusick int flag;
302053901Smckusick {
302153901Smckusick register struct iop/**/_device *ii;
302253901Smckusick register struct sc_ureq *scu;
302353901Smckusick register struct sdst *st;
302453901Smckusick register struct scsi *sc;
302553901Smckusick register int unit;
302653901Smckusick register int ctlr;
302753901Smckusick register int slave;
302853901Smckusick struct sdc_softc *sdc;
302953901Smckusick struct sdd_softc *sdd;
303053901Smckusick struct Partinfo *pi;
303153901Smckusick struct dkst *di;
303253901Smckusick struct buf *bp;
303353901Smckusick struct sddevinfo *sdi;
303453901Smckusick struct sdst *stp;
303553901Smckusick struct scsi uscsi;
303653901Smckusick int error;
303753901Smckusick int i;
303853901Smckusick int s;
303953901Smckusick int tstatus;
304053901Smckusick char *p;
304153901Smckusick int blkno, count;
304253901Smckusick
304353901Smckusick unit = dev2unit(dev);
304453901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
304553901Smckusick return (ENXIO);
304653901Smckusick
304753901Smckusick slave = ii->ii_slave;
304853901Smckusick ctlr = ii->ii_ctlr;
304953901Smckusick sdc = &sdc_softc[ctlr];
305053901Smckusick sdd = &sdd_softc[unit];
305153901Smckusick sc = &uscsi;
305253901Smckusick
305353901Smckusick error = 0;
305453901Smckusick switch (cmd) {
305553901Smckusick
305653901Smckusick case DIOCWLABEL:
305753901Smckusick if (*(int *)data & SD_F_ENW)
305853901Smckusick ii->ii_flags |= SD_F_ENW;
305953901Smckusick else
306053901Smckusick ii->ii_flags &= ~SD_F_ENW;
306153901Smckusick break;
306253901Smckusick
306353901Smckusick case DIOCGDINFO:
306453901Smckusick *(struct disklabel *)data = sdlabel[unit];
306553901Smckusick break;
306653901Smckusick
306753901Smckusick case DIOCSDINFO:
306853901Smckusick sdlabel[unit] = *(struct disklabel *)data;
306953901Smckusick disklabel2sdst(unit, &sdlabel[unit], &sdstdrv[unit]);
307053901Smckusick break;
307153901Smckusick
307253901Smckusick case DIOCWDINFO:
307353901Smckusick case DKIOCRGEOM:
307453901Smckusick switch (cmd) {
307553901Smckusick case DKIOCRGEOM:
307653901Smckusick st = &sdstdrv[unit];
307753901Smckusick sdi = &sddevinfo[ii->ii_type];
307853901Smckusick stp = sdi->sdstp;
307953901Smckusick
308053901Smckusick st->ncyl = stp->ncyl; /* # cylinders / drive */
308153901Smckusick st->ntrak = stp->ntrak; /* # tracks / cylinder */
308253901Smckusick st->nsect = stp->nsect; /* # sectors / track */
308353901Smckusick st->rps = stp->rps; /* # revolutions / second */
308453901Smckusick
308553901Smckusick sdst2disklabel(unit, st, &sdlabel[unit]);
308653901Smckusick
308753901Smckusick if (*(int *)data == RGEOM_SDINFO)
308853901Smckusick goto done;
308953901Smckusick
309053901Smckusick break;
309153901Smckusick
309253901Smckusick case DIOCWDINFO:
309353901Smckusick sdlabel[unit] = *(struct disklabel *)data;
309453901Smckusick
309553901Smckusick break;
309653901Smckusick }
309753901Smckusick
309853901Smckusick /*
309953901Smckusick * Common code for DIOCWDINFO and DKIOCRGEOM
310053901Smckusick */
310153901Smckusick
310253901Smckusick /**** READ sector 0 ****/
310353901Smckusick /*
310453901Smckusick * LOCK sdtmp buffer
310553901Smckusick */
310653901Smckusick s = splclock();
310753901Smckusick while (sdtmp_stat & B_BUSY) {
310853901Smckusick sdtmp_stat |= B_WANTED;
310953901Smckusick sleep((caddr_t)sdtmp, PRIBIO);
311053901Smckusick }
311153901Smckusick sdtmp_stat |= B_BUSY;
311253901Smckusick splx(s);
311353901Smckusick
311453901Smckusick bzero(sdtmp, DEV_BSIZE);
311553901Smckusick
311653901Smckusick if ((sdd->sdd_flags & SDDF_NONFMT) == 0) {
311753901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
311853901Smckusick uscsi.sc_cpoint = sdtmp;
311953901Smckusick uscsi.sc_ctrnscnt = DEV_BSIZE;
312053901Smckusick uscsi.sc_opcode = SCOP_READ;
312153901Smckusick uscsi.sc_lad = 0;
312253901Smckusick uscsi.sc_count = 1;
312353901Smckusick error = sdcmd(dev, &uscsi);
312453901Smckusick } else {
312553901Smckusick error = EIO;
312653901Smckusick }
312753901Smckusick
312853901Smckusick if (error) {
312953901Smckusick /*
313053901Smckusick * UNLOCK sdtmp buffer
313153901Smckusick */
313253901Smckusick s = splclock();
313353901Smckusick if (sdtmp_stat & B_WANTED)
313453901Smckusick wakeup((caddr_t)sdtmp);
313553901Smckusick sdtmp_stat &= ~(B_BUSY|B_WANTED);
313653901Smckusick splx(s);
313753901Smckusick
313853901Smckusick break;
313953901Smckusick }
314053901Smckusick
314153901Smckusick *(struct disklabel *)(sdtmp + LABELOFFSET) = sdlabel[unit];
314253901Smckusick
314353901Smckusick /**** WRITE sector 0 ****/
314453901Smckusick
314553901Smckusick if (error == 0) {
314653901Smckusick if ((sdd->sdd_flags & SDDF_NONFMT) == 0) {
314753901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
314853901Smckusick uscsi.sc_cpoint = sdtmp;
314953901Smckusick uscsi.sc_ctrnscnt = DEV_BSIZE;
315053901Smckusick uscsi.sc_opcode = SCOP_WRITE;
315153901Smckusick
315253901Smckusick uscsi.sc_lad = 0;
315353901Smckusick uscsi.sc_count = 1;
315453901Smckusick
315553901Smckusick error = sdcmd(dev, &uscsi);
315653901Smckusick } else
315753901Smckusick error = EIO;
315853901Smckusick }
315953901Smckusick
316053901Smckusick /*
316153901Smckusick * UNLOCK sdtmp buffer
316253901Smckusick */
316353901Smckusick s = splclock();
316453901Smckusick if (sdtmp_stat & B_WANTED)
316553901Smckusick wakeup((caddr_t)sdtmp);
316653901Smckusick sdtmp_stat &= ~(B_BUSY|B_WANTED);
316753901Smckusick splx(s);
316853901Smckusick
316953901Smckusick disklabel2sdst(unit, &sdlabel[unit], &sdstdrv[unit]);
317053901Smckusick
317153901Smckusick break;
317253901Smckusick
317353901Smckusick case DKIOCGGEOM:
317453901Smckusick st = &sdstdrv[unit];
317553901Smckusick di = (struct dkst *)data;
317653901Smckusick
317753901Smckusick di->dks_ncyl = st->ncyl; /* # cylinders / drive */
317853901Smckusick di->dks_ntrak = st->ntrak; /* # tracks / cylinder */
317953901Smckusick di->dks_nsect = st->nsect; /* # sectors / track */
318053901Smckusick di->dks_rps = st->rps; /* # revolutions / second */
318153901Smckusick
318253901Smckusick break;
318353901Smckusick
318453901Smckusick case DKIOCSGEOM:
318553901Smckusick st = &sdstdrv[unit];
318653901Smckusick di = (struct dkst *)data;
318753901Smckusick
318853901Smckusick st->ncyl = di->dks_ncyl; /* # cylinders / drive */
318953901Smckusick st->ntrak = di->dks_ntrak; /* # tracks / cylinder */
319053901Smckusick st->nsect = di->dks_nsect; /* # sectors / track */
319153901Smckusick st->rps = di->dks_rps; /* # revolutions / second */
319253901Smckusick
319353901Smckusick sdst2disklabel(unit, st, &sdlabel[unit]);
319453901Smckusick break;
319553901Smckusick
319653901Smckusick case DKIOCGPART:
319753901Smckusick case DKIOCSPART:
319853901Smckusick /*
319953901Smckusick * partition information
320053901Smckusick */
320153901Smckusick st = &sdstdrv[unit];
320253901Smckusick pi = (struct Partinfo *)data;
320353901Smckusick
320453901Smckusick if (cmd == DKIOCGPART) {
320553901Smckusick pi->dp_nblocks = st->sizes[dev2part(dev)].sd_nblocks;
320653901Smckusick pi->dp_blkoff = st->sizes[dev2part(dev)].sd_blkoff;
320753901Smckusick } else {
320853901Smckusick st->sizes[dev2part(dev)].sd_nblocks = pi->dp_nblocks;
320953901Smckusick st->sizes[dev2part(dev)].sd_blkoff = pi->dp_blkoff;
321053901Smckusick
321153901Smckusick sdst2disklabel(unit, st, &sdlabel[unit]);
321253901Smckusick }
321353901Smckusick break;
321453901Smckusick
321553901Smckusick case DKIOCGUNIT:
321653901Smckusick *(int *)data = slave;
321753901Smckusick break;
321853901Smckusick
321953901Smckusick case DKIOCGCHAN:
322053901Smckusick *(int *)data = ii->ii_intr;
322153901Smckusick break;
322253901Smckusick
322353901Smckusick case DKIOCSEEK:
322453901Smckusick scinit(sc, slave, sdd->sdd_sectsize);
322553901Smckusick sc->sc_opcode = SCOP_SEEK;
322653901Smckusick sc->sc_lad = *(int *)data;
322753901Smckusick
322853901Smckusick (void) sdcmd(dev, sc);
322953901Smckusick tstatus = sc->sc_tstatus & TGSTMASK;
323053901Smckusick if ((sc->sc_istatus != INST_EP) || (tstatus != TGST_GOOD))
323153901Smckusick error = ESPIPE;
323253901Smckusick break;
323353901Smckusick
323453901Smckusick case DKIOCRSEC0:
323553901Smckusick case DKIOCRBOOT1:
323653901Smckusick case DKIOCRBOOT:
323753901Smckusick if (sdd->sdd_flags & SDDF_NONFMT) {
323853901Smckusick error = EIO;
323953901Smckusick break;
324053901Smckusick }
324153901Smckusick switch (cmd) {
324253901Smckusick
324353901Smckusick case DKIOCRSEC0:
324453901Smckusick blkno = 0;
324553901Smckusick count = 1;
324653901Smckusick break;
324753901Smckusick
324853901Smckusick case DKIOCRBOOT1:
324953901Smckusick blkno = 1;
325053901Smckusick count = 15;
325153901Smckusick break;
325253901Smckusick
325353901Smckusick default:
325453901Smckusick blkno = 0;
325553901Smckusick count = 16;
325653901Smckusick }
325753901Smckusick p = (char *)*(int *)data;
325853901Smckusick for (i = 0; !error && i < count; i++) {
325953901Smckusick s = splclock();
326053901Smckusick while (sdtmp_stat & B_BUSY) {
326153901Smckusick sdtmp_stat |= B_WANTED;
326253901Smckusick sleep((caddr_t)sdtmp, PRIBIO);
326353901Smckusick }
326453901Smckusick sdtmp_stat |= B_BUSY;
326553901Smckusick splx(s);
326653901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
326753901Smckusick uscsi.sc_cpoint = sdtmp;
326853901Smckusick uscsi.sc_ctrnscnt = DEV_BSIZE;
326953901Smckusick uscsi.sc_opcode = SCOP_READ;
327053901Smckusick uscsi.sc_lad = blkno;
327153901Smckusick uscsi.sc_count = 1;
327253901Smckusick if (error = sdcmd(dev, &uscsi))
327353901Smckusick goto dkior_done;
327453901Smckusick if (error = copyout(sdtmp, p, DEV_BSIZE))
327553901Smckusick goto dkior_done;
327653901Smckusick blkno++;
327753901Smckusick p += DEV_BSIZE;
327853901Smckusick
327953901Smckusick dkior_done:
328053901Smckusick s = splclock();
328153901Smckusick if (sdtmp_stat & B_WANTED)
328253901Smckusick wakeup((caddr_t)sdtmp);
328353901Smckusick sdtmp_stat &= ~(B_BUSY|B_WANTED);
328453901Smckusick splx(s);
328553901Smckusick }
328653901Smckusick break;
328753901Smckusick
328853901Smckusick case DKIOCWSEC0:
328953901Smckusick case DKIOCWBOOT1:
329053901Smckusick case DKIOCWBOOT:
329153901Smckusick if (sdd->sdd_flags & SDDF_NONFMT) {
329253901Smckusick error = EIO;
329353901Smckusick break;
329453901Smckusick }
329553901Smckusick switch (cmd) {
329653901Smckusick
329753901Smckusick case DKIOCWSEC0:
329853901Smckusick blkno = 0;
329953901Smckusick count = 1;
330053901Smckusick break;
330153901Smckusick
330253901Smckusick case DKIOCWBOOT1:
330353901Smckusick blkno = 1;
330453901Smckusick count = 15;
330553901Smckusick break;
330653901Smckusick
330753901Smckusick default:
330853901Smckusick blkno = 0;
330953901Smckusick count = 16;
331053901Smckusick }
331153901Smckusick p = (char *)*(int *)data;
331253901Smckusick for (i = 0; !error && i < count; i++) {
331353901Smckusick s = splclock();
331453901Smckusick while (sdtmp_stat & B_BUSY) {
331553901Smckusick sdtmp_stat |= B_WANTED;
331653901Smckusick sleep(sdtmp, PRIBIO);
331753901Smckusick }
331853901Smckusick sdtmp_stat |= B_BUSY;
331953901Smckusick splx(s);
332053901Smckusick if (error = copyin(p, sdtmp, DEV_BSIZE))
332153901Smckusick goto dkiow_done;
332253901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
332353901Smckusick uscsi.sc_cpoint = sdtmp;
332453901Smckusick uscsi.sc_ctrnscnt = DEV_BSIZE;
332553901Smckusick uscsi.sc_opcode = SCOP_WRITE;
332653901Smckusick uscsi.sc_lad = blkno;
332753901Smckusick uscsi.sc_count = 1;
332853901Smckusick if (error = sdcmd(dev, &uscsi))
332953901Smckusick goto dkiow_done;
333053901Smckusick blkno++;
333153901Smckusick p += DEV_BSIZE;
333253901Smckusick
333353901Smckusick dkiow_done:
333453901Smckusick s = splclock();
333553901Smckusick if (sdtmp_stat & B_WANTED)
333653901Smckusick wakeup(sdtmp);
333753901Smckusick sdtmp_stat &= ~(B_BUSY|B_WANTED);
333853901Smckusick splx(s);
333953901Smckusick }
334053901Smckusick break;
334153901Smckusick
334253901Smckusick case SDIOC_PRVRMV:
334353901Smckusick case SDIOC_ALWRMV:
334453901Smckusick /*
334553901Smckusick * prevent/allow medium removal
334653901Smckusick */
334753901Smckusick scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
334853901Smckusick sc->sc_opcode = SCOP_MEDRMV;
334953901Smckusick sc->sc_count = (cmd==SDIOC_PRVRMV)? SDRMV_PREV : SDRMV_ALLOW;
335053901Smckusick if (cmd == SDIOC_PRVRMV)
335153901Smckusick sdd->sdd_flags |= SDDF_INHRMV;
335253901Smckusick else
335353901Smckusick sdd->sdd_flags &= ~SDDF_INHRMV;
335453901Smckusick
335553901Smckusick error = sdcmd(dev, sc);
335653901Smckusick break;
335753901Smckusick
335853901Smckusick case SDIOC_SXUSE:
335953901Smckusick if (isalone(unit) != ONLY_ONE)
336053901Smckusick return (EBUSY);
336153901Smckusick sdd->sdd_flags |= SDDF_XUSE;
336253901Smckusick break;
336353901Smckusick
336453901Smckusick case SDIOC_RXUSE:
336553901Smckusick sdd->sdd_flags &= ~SDDF_XUSE;
336653901Smckusick break;
336753901Smckusick
336853901Smckusick case SDIOC_ERSON:
336953901Smckusick sdd->sdd_flags &= ~SDDF_ERASEOFF;
337053901Smckusick break;
337153901Smckusick
337253901Smckusick case SDIOC_ERSOFF:
337353901Smckusick if ((sdd->sdd_flags & SDDF_XUSE) != 0)
337453901Smckusick return (EBUSY);
337553901Smckusick sdd->sdd_flags |= SDDF_ERASEOFF;
337653901Smckusick sdd->sdd_flags &= ~SDDF_NONFMT;
337753901Smckusick break;
337853901Smckusick
337953901Smckusick case SDIOC_FORMAT:
338053901Smckusick /*
338153901Smckusick * format unit
338253901Smckusick */
338353901Smckusick if ((flag & FWRITE) == 0)
338453901Smckusick return (EINVAL);
338553901Smckusick if (isalone(unit) != ONLY_ONE)
338653901Smckusick return (EBUSY);
338753901Smckusick sdd->sdd_flags |= SDDF_XUSE;
338853901Smckusick sdd->sdd_flags &= ~(SDDF_NONFMT|SDDF_FMTDONE|SDDF_SAMEDSK);
338953901Smckusick scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
339053901Smckusick sc->sc_ctrnscnt = 4;
339153901Smckusick sc->sc_opcode = SCOP_FMT;
339253901Smckusick
339353901Smckusick sc->sc_lad = ((sddevinfo[ii->ii_type].fmt_opts & FMT_DLFMT)
339453901Smckusick | SDF_FMTDAT) << 16;
339553901Smckusick
339653901Smckusick switch (sddevinfo[ii->ii_type].type) {
339753901Smckusick
339853901Smckusick case SMO_S501:
339953901Smckusick case SMO_S501_ISO:
340053901Smckusick case SMO_S501_ISO2:
340153901Smckusick sc->sc_lad |= ((SDF_MKCDA|SDF_MKPLST) << 8);
340253901Smckusick break;
340353901Smckusick
340453901Smckusick default:
340553901Smckusick break;
340653901Smckusick }
340753901Smckusick
340853901Smckusick {
340953901Smckusick struct fmt_data *fdata = (struct fmt_data *)data;
341053901Smckusick
341153901Smckusick error = copyin((caddr_t)fdata->dlh, sc->sc_param, 4);
341253901Smckusick if (error != 0) {
341353901Smckusick sdd->sdd_flags &= ~SDDF_XUSE;
341453901Smckusick break;
341553901Smckusick }
341653901Smckusick if (fdata->noglist)
341753901Smckusick sc->sc_lad |= (SDF_CMPLST<<16);
341853901Smckusick }
341953901Smckusick
342053901Smckusick if (sdd->sdd_flags & SDDF_ERASEOFF)
342153901Smckusick sc->sc_ctrl = 0x40;
342253901Smckusick
342353901Smckusick error = sdcmd(dev, sc);
342453901Smckusick sdd->sdd_flags &= ~SDDF_XUSE;
342553901Smckusick break;
342653901Smckusick
342753901Smckusick case SDIOC_FORMAT2:
342853901Smckusick /*
342953901Smckusick * format unit
343053901Smckusick */
343153901Smckusick if ((flag & FWRITE) == 0)
343253901Smckusick return (EINVAL);
343353901Smckusick if (isalone(unit) != ONLY_ONE)
343453901Smckusick return (EBUSY);
343553901Smckusick sdd->sdd_flags |= SDDF_XUSE;
343653901Smckusick sdd->sdd_flags &= ~(SDDF_NONFMT|SDDF_FMTDONE|SDDF_SAMEDSK);
343753901Smckusick
343853901Smckusick scu = (struct sc_ureq *)data;
343953901Smckusick error = sd_scu_exec(dev, scu, sc);
344053901Smckusick sdd->sdd_flags &= ~SDDF_XUSE;
344153901Smckusick break;
344253901Smckusick
344353901Smckusick case SDIOC_GSTOPT:
344453901Smckusick case SDIOC_SSTOPT:
344553901Smckusick /*
344653901Smckusick * get/set stop-unit timer
344753901Smckusick */
344853901Smckusick if (cmd == SDIOC_GSTOPT)
344953901Smckusick *(int *)data = sdd->sdd_stoptime;
345053901Smckusick else {
345153901Smckusick if (*(int *)data == 0)
345253901Smckusick return (EINVAL);
345353901Smckusick sdd->sdd_stoptime = *(int *)data;
345453901Smckusick }
345553901Smckusick break;
345653901Smckusick
345753901Smckusick case SDIOC_SEJECT:
345853901Smckusick /*
345953901Smckusick * set auto eject flag
346053901Smckusick */
346153901Smckusick sdd->sdd_flags |= SDDF_REQ_EJECT;
346253901Smckusick break;
346353901Smckusick
346453901Smckusick case SDIOC_GFLAGS:
346553901Smckusick /*
346653901Smckusick * get ii->ii_flags
346753901Smckusick */
346853901Smckusick *(int *)data = ii->ii_flags;
346953901Smckusick break;
347053901Smckusick
347153901Smckusick case SDIOC_SFLAGS:
347253901Smckusick /*
347353901Smckusick * set ii->ii_flags
347453901Smckusick */
347553901Smckusick ii->ii_flags = *(int *)data;
347653901Smckusick break;
347753901Smckusick
347853901Smckusick case SDIOC_RASBLK:
347953901Smckusick /*
348053901Smckusick * reassign block
348153901Smckusick */
348253901Smckusick {
348353901Smckusick struct sc_rab *sca = (struct sc_rab *)sc->sc_param;
348453901Smckusick
348553901Smckusick scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
348653901Smckusick sc->sc_opcode = SCOP_RASBLK;
348753901Smckusick sc->sc_ctrnscnt = 8;
348853901Smckusick
348953901Smckusick sca->sca_dllen = 4;
349053901Smckusick sca->sca_dlad[0] = *(int *)data;
349153901Smckusick
349253901Smckusick error = sdcmd(dev, sc);
349353901Smckusick }
349453901Smckusick break;
349553901Smckusick
349653901Smckusick case SDIOC_GNICKNAME:
349753901Smckusick {
349853901Smckusick int len;
349953901Smckusick
350053901Smckusick len = strlen(sddevinfo[ii->ii_type].call_name);
350153901Smckusick
350253901Smckusick if (len > IOCPARM_MASK)
350353901Smckusick len = IOCPARM_MASK;
350453901Smckusick
350553901Smckusick error = copyout(
350653901Smckusick (caddr_t) sddevinfo[ii->ii_type].call_name,
350753901Smckusick (caddr_t) *(int *)data,
350853901Smckusick len);
350953901Smckusick }
351053901Smckusick break;
351153901Smckusick
351253901Smckusick case SDIOC_GTYPINDEX:
351353901Smckusick *(int *)data = (int)ii->ii_type;
351453901Smckusick break;
351553901Smckusick
351653901Smckusick #ifdef SDIOC_SSYNCPARAM
351753901Smckusick case SDIOC_SSYNCPARAM:
351853901Smckusick {
351953901Smckusick struct sync_param *syncp;
352053901Smckusick
352153901Smckusick syncp = (struct sync_param *)data;
352253901Smckusick scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
352353901Smckusick sc->sc_opcode = SCOP_TST;
352453901Smckusick sc->sc_message = MSG_EXTND; /* extended message */
352553901Smckusick sc->sc_param[0] = MSG_EXTND;
352653901Smckusick sc->sc_param[1] = 0x03;
352753901Smckusick sc->sc_param[2] = 0x01; /* synchronous transfer */
352853901Smckusick sc->sc_param[3] = syncp->tr_period; /* transfer period */
352953901Smckusick sc->sc_param[4] = syncp->tr_offset; /* REQ offset */
353053901Smckusick
353153901Smckusick (void) sdcmd(dev, sc);
353253901Smckusick
353353901Smckusick syncp = &sd_sync_param[unit];
353453901Smckusick syncp->tr_period = sc->sc_param[3];
353553901Smckusick syncp->tr_offset = sc->sc_param[4];
353653901Smckusick
353753901Smckusick if (syncp->tr_offset)
353853901Smckusick sdd->sdd_flags |= SDDF_SYNCTR;
353953901Smckusick else
354053901Smckusick sdd->sdd_flags &= ~SDDF_SYNCTR;
354153901Smckusick }
354253901Smckusick break;
354353901Smckusick
354453901Smckusick case SDIOC_GSYNCPARAM:
354553901Smckusick {
354653901Smckusick struct sync_param *syncp = (struct sync_param *)data;
354753901Smckusick
354853901Smckusick syncp->tr_period = sd_sync_param[unit].tr_period;
354953901Smckusick syncp->tr_offset = sd_sync_param[unit].tr_offset;
355053901Smckusick }
355153901Smckusick break;
355253901Smckusick #endif /* SDIOC_SSYNCPARAM */
355353901Smckusick
355453901Smckusick case MTIOCTOP:
355553901Smckusick {
355653901Smckusick register struct mtop *mtop = (struct mtop *)data;
355753901Smckusick register int lba;
355853901Smckusick int rest;
355953901Smckusick int blength;
356053901Smckusick
356153901Smckusick switch (mtop->mt_op) {
356253901Smckusick
356353901Smckusick case MTOFFL:
356453901Smckusick /*
356553901Smckusick * set auto eject flag
356653901Smckusick */
356753901Smckusick sdd->sdd_flags |= SDDF_REQ_EJECT;
356853901Smckusick break;
356953901Smckusick
357053901Smckusick #ifdef MTERASE
357153901Smckusick case MTERASE:
357253901Smckusick if (isalone(unit) != ONLY_ONE)
357353901Smckusick return (EBUSY);
357453901Smckusick sdd->sdd_flags |= SDDF_XUSE;
357553901Smckusick st = &sdstdrv[unit];
357653901Smckusick /*
357753901Smckusick * MO disk erase
357853901Smckusick * block 0 to end (C partition)
357953901Smckusick */
358053901Smckusick lba = 0;
358153901Smckusick rest = sdd->sdd_nsect; /* C part size */
358253901Smckusick while (rest > 0) {
358353901Smckusick blength = (rest > MAXBL)? MAXBL : rest;
358453901Smckusick scinit(sc, ii->ii_slave,
358553901Smckusick sdd->sdd_sectsize);
358653901Smckusick sc->sc_opcode = SCOP_MOERASE;
358753901Smckusick sc->sc_lad = lba;
358853901Smckusick sc->sc_count = (blength % MAXBL);
358953901Smckusick
359053901Smckusick (void) sdcmd(dev, sc);
359153901Smckusick lba += blength;
359253901Smckusick rest -= blength;
359353901Smckusick }
359453901Smckusick sdd->sdd_flags &= ~SDDF_XUSE;
359553901Smckusick break;
359653901Smckusick #endif /* MTERASE */
359753901Smckusick
359853901Smckusick default:
359953901Smckusick return (EINVAL);
360053901Smckusick }
360153901Smckusick }
360253901Smckusick break;
360353901Smckusick
360453901Smckusick case SCSIIOCCMD:
360553901Smckusick scu = (struct sc_ureq *)data;
360653901Smckusick if ((scu->scu_count > 0) && scu->scu_addr) {
360753901Smckusick if (useracc(scu->scu_addr, scu->scu_count, B_WRITE)
360853901Smckusick == NULL) {
360953901Smckusick error = EFAULT;
361053901Smckusick break;
361153901Smckusick }
361253901Smckusick }
361353901Smckusick error = sd_scu_exec(dev, scu, sc);
361453901Smckusick break;
361553901Smckusick
361653901Smckusick
361753901Smckusick case SDIOC_INQUIRY:
361853901Smckusick /*
361953901Smckusick * LOCK sdtmp buffer
362053901Smckusick */
362153901Smckusick s = splclock();
362253901Smckusick while (sdtmp_stat & B_BUSY) {
362353901Smckusick sdtmp_stat |= B_WANTED;
362453901Smckusick sleep((caddr_t)sdtmp, PRIBIO);
362553901Smckusick }
362653901Smckusick sdtmp_stat |= B_BUSY;
362753901Smckusick splx(s);
362853901Smckusick
362953901Smckusick bzero((caddr_t)sdtmp, sizeof(struct sc_inq));
363053901Smckusick scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
363153901Smckusick uscsi.sc_cpoint = sdtmp;
363253901Smckusick uscsi.sc_ctrnscnt = sizeof(struct sc_inq);
363353901Smckusick uscsi.sc_opcode = SCOP_INQUIRY;
363453901Smckusick uscsi.sc_count = sizeof(struct sc_inq);
363553901Smckusick
363653901Smckusick if ((error = sdcmd(dev, &uscsi)) == 0)
363753901Smckusick bcopy((caddr_t)sdtmp, data, sizeof(struct sc_inq));
363853901Smckusick /*
363953901Smckusick * UNLOCK open
364053901Smckusick */
364153901Smckusick s = splclock();
364253901Smckusick if (sdtmp_stat & B_WANTED)
364353901Smckusick wakeup((caddr_t)sdtmp);
364453901Smckusick sdtmp_stat &= ~(B_BUSY|B_WANTED);
364553901Smckusick splx(s);
364653901Smckusick break;
364753901Smckusick
364853901Smckusick
364953901Smckusick case SCSIIOCGTIMEO:
365053901Smckusick *(int *)data = sdc->sdc_timeo;
365153901Smckusick break;
365253901Smckusick
365353901Smckusick case SCSIIOCSTIMEO:
365453901Smckusick if (*(int *)data == 0)
365553901Smckusick return (EINVAL);
365653901Smckusick sdc->sdc_timeo = *(int *)data;
365753901Smckusick sdc->sdc_wticks = 0;
365853901Smckusick break;
365953901Smckusick
366053901Smckusick default:
366153901Smckusick error = EINVAL;
366253901Smckusick break;
366353901Smckusick }
366453901Smckusick
366553901Smckusick done:
366653901Smckusick return (error);
366753901Smckusick }
366853901Smckusick
366953901Smckusick static
sd_scu_exec(dev,scu,sc)367053901Smckusick sd_scu_exec(dev, scu, sc)
367153901Smckusick dev_t dev;
367253901Smckusick register struct sc_ureq *scu;
367353901Smckusick register struct scsi *sc;
367453901Smckusick {
367553901Smckusick struct sdd_softc *sdd;
367653901Smckusick int error;
367753901Smckusick
367853901Smckusick sdd = &sdd_softc[dev2unit(dev)];
367953901Smckusick
368053901Smckusick if (((scu->scu_identify & MSG_IDENT) == 0)
368153901Smckusick || (scu->scu_identify & ~(MSG_IDENT|IDT_DISCON|IDT_DRMASK))
368253901Smckusick || (scu->scu_addr && (scu->scu_bytesec == 0))) {
368353901Smckusick return (EINVAL);
368453901Smckusick }
368553901Smckusick
368653901Smckusick bzero((caddr_t)sc, sizeof(struct scsi));
368753901Smckusick sc->sc_tstatus = scu->scu_tstatus;
368853901Smckusick sc->sc_identify = scu->scu_identify;
368953901Smckusick sc->sc_message = scu->scu_message;
369053901Smckusick sc->sc_bytesec = scu->scu_bytesec;
369153901Smckusick sc->sc_cpoint = scu->scu_addr;
369253901Smckusick sc->sc_ctrnscnt = scu->scu_count;
369353901Smckusick bcopy((caddr_t)scu->scu_cdb, &sc->sc_cdb, sizeof(sc->sc_cdb));
369453901Smckusick
369553901Smckusick bcopy((caddr_t)scu->scu_param, (caddr_t)sc->sc_param,
369653901Smckusick sizeof(sc->sc_param));
369753901Smckusick
369853901Smckusick sdd->sdd_flags |= SDDF_SKIPCHECK;
369953901Smckusick error = sdcmd(dev, sc);
370053901Smckusick sdd->sdd_flags &= ~SDDF_SKIPCHECK;
370153901Smckusick
370253901Smckusick scu->scu_istatus = sc->sc_istatus;
370353901Smckusick scu->scu_tstatus = sc->sc_tstatus;
370453901Smckusick scu->scu_message = sc->sc_message;
370553901Smckusick bcopy((caddr_t)sc->sc_param, (caddr_t)scu->scu_param,
370653901Smckusick sizeof(sc->sc_param));
370753901Smckusick return (error);
370853901Smckusick }
370953901Smckusick
371053901Smckusick /*ARGSUSED*/
sddump(dev)371153901Smckusick sddump(dev)
371253901Smckusick dev_t dev;
371353901Smckusick {
371453901Smckusick return (ENXIO);
371553901Smckusick }
371653901Smckusick
sdsize(dev)371753901Smckusick sdsize(dev)
371853901Smckusick register dev_t dev;
371953901Smckusick {
372053901Smckusick register struct iop/**/_device *ii;
372153901Smckusick register struct sdd_softc *sdd;
372253901Smckusick register struct sdst *st;
372353901Smckusick register int unit;
372453901Smckusick int i;
372553901Smckusick
372653901Smckusick unit = dev2unit(dev);
372753901Smckusick if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
372853901Smckusick return (-1);
372953901Smckusick
373053901Smckusick sdd = &sdd_softc[unit];
373153901Smckusick switch (sdc_softc[ii->ii_ctlr].sdc_firmware & SDCFW_DEVMASK) {
373253901Smckusick
373353901Smckusick case SDCFW_HD: /* Hard Disk */
373453901Smckusick st = &sdstdrv[unit];
373553901Smckusick break;
373653901Smckusick
373753901Smckusick case SDCFW_MO: /* MO only */
373853901Smckusick if ((sdd->sdd_flags & SDDF_SAMEDSK) == SDDF_DSKCHGD) {
373953901Smckusick /*
374053901Smckusick * read partition information,
374153901Smckusick * and set up sdstdrv[unit]
374253901Smckusick */
374353901Smckusick if (sd_b_open(dev, FREAD|FWRITE) != 0) {
374453901Smckusick /*
374553901Smckusick * block device open error
374653901Smckusick */
374753901Smckusick return (-1);
374853901Smckusick } else {
374953901Smckusick /*
375053901Smckusick * use disk partition information
375153901Smckusick */
375253901Smckusick st = &sdstdrv[unit];
375353901Smckusick if (isalone(unit) == ONLY_ONE)
375453901Smckusick sd_b_close(dev, 0);
375553901Smckusick }
375653901Smckusick } else if (sdd->sdd_flags & SDDF_NONFMT) {
375753901Smckusick /*
375853901Smckusick * medium is not initialized.
375953901Smckusick */
376053901Smckusick return (-1);
376153901Smckusick } else {
376253901Smckusick st = &sdstdrv[unit];
376353901Smckusick }
376453901Smckusick break;
376553901Smckusick
376653901Smckusick default:
376753901Smckusick /* case SDCFW_CD: */
376853901Smckusick return (-1);
376953901Smckusick
377053901Smckusick }
377153901Smckusick
377253901Smckusick if (st->sizes == NULL)
377353901Smckusick return (-1); /* XXX */
377453901Smckusick else
377553901Smckusick return (st->sizes[dev2part(dev)].sd_nblocks); /* XXX */
377653901Smckusick }
377753901Smckusick
377853901Smckusick /*
377953901Smckusick * Reset driver.
378053901Smckusick * Cancel software state of all pending transfers,
378153901Smckusick * and restart all units and the controller.
378253901Smckusick */
sdreset()378353901Smckusick sdreset()
378453901Smckusick {
378553901Smckusick register struct iop/**/_ctlr *im;
378653901Smckusick register struct iop/**/_device *ii;
378753901Smckusick register struct sdc_softc *sdc;
378853901Smckusick register struct sdd_softc *sdd;
378953901Smckusick register int i;
379053901Smckusick register int unit;
379153901Smckusick
379253901Smckusick re_init_done = 1;
379353901Smckusick for (i = 0; i < nsdc; i++) {
379453901Smckusick im = sdminfo[i];
379553901Smckusick if (im == 0)
379653901Smckusick continue;
379753901Smckusick if (im->im_alive == 0)
379853901Smckusick continue;
379953901Smckusick printf(" sdc%d: ", i);
380053901Smckusick sdc = &sdc_softc[i];
380153901Smckusick sdc->sdc_wticks = 0;
380253901Smckusick
380353901Smckusick /* scop_init() is already called by screset() */
380453901Smckusick
380553901Smckusick sdtmp_stat &= ~B_BUSY;
380653901Smckusick
380753901Smckusick for (unit = 0; unit < nsd; unit++) {
380853901Smckusick ii = sddinfo[unit];
380953901Smckusick if (ii == 0)
381053901Smckusick continue;
381153901Smckusick if (ii->ii_alive == 0)
381253901Smckusick continue;
381353901Smckusick if (ii->ii_mi != im)
381453901Smckusick continue;
381553901Smckusick
381653901Smckusick csdbuf[unit].b_flags &= ~B_BUSY;
381753901Smckusick
381853901Smckusick sdd = &sdd_softc[unit];
381953901Smckusick sdd->sdd_flags = 0;
382053901Smckusick
382153901Smckusick /*
382253901Smckusick * UNLOCK SCSI access
382353901Smckusick */
382453901Smckusick sdc->sdc_firmware &= ~SDCFW_BUSY;
382553901Smckusick
382653901Smckusick if (sdslave(ii, ii->ii_addr, im->im_intr) == 0) {
382753901Smckusick printf("sd%d: not ready\n", ii->ii_slave);
382853901Smckusick continue;
382953901Smckusick }
383053901Smckusick sdattach(ii);
383153901Smckusick }
383253901Smckusick }
383353901Smckusick re_init_done = 2;
383453901Smckusick }
383553901Smckusick
383653901Smckusick int sd_long_timeout = 24 * 60 * 60; /* 24 hours */
383753901Smckusick
383853901Smckusick #define max(a, b) (((a)>(b))?(a):(b))
383953901Smckusick
384053901Smckusick /*
384153901Smckusick * Wake up every second and if interrupt is pending
384253901Smckusick * but nothing has happened increment a counter.
384353901Smckusick * If nothing happens for sdc_timeo seconds, reset the IOP
384453901Smckusick * and begin anew.
384553901Smckusick */
sdwatch()384653901Smckusick sdwatch()
384753901Smckusick {
384853901Smckusick register struct iop/**/_ctlr *im;
384953901Smckusick register struct sdc_softc *sdc;
385053901Smckusick register int i;
385153901Smckusick register int unit;
385253901Smckusick int timeo;
385353901Smckusick
385453901Smckusick extern int Scsi_Disconnect;
385553901Smckusick
385653901Smckusick timeout(sdwatch, (caddr_t)0, hz);
385753901Smckusick for (i = 0; i < nsdc; i++) {
385853901Smckusick im = sdminfo[i];
385953901Smckusick if (im == 0)
386053901Smckusick continue;
386153901Smckusick if (im->im_alive == 0)
386253901Smckusick continue;
386353901Smckusick sdc = &sdc_softc[i];
386453901Smckusick
386553901Smckusick if (im->im_tab.b_active)
386653901Smckusick goto active;
386753901Smckusick
386853901Smckusick for (unit = 0; unit < nsd; unit++)
386953901Smckusick if (sdutab[unit].b_active && sddinfo[unit]->ii_mi == im)
387053901Smckusick goto active;
387153901Smckusick
387253901Smckusick sdc->sdc_wticks = 0;
387353901Smckusick continue;
387453901Smckusick active:
387553901Smckusick if (Scsi_Disconnect)
387653901Smckusick timeo = sdc->sdc_timeo;
387753901Smckusick else
387853901Smckusick timeo = max(sdc->sdc_timeo, sd_long_timeout);
387953901Smckusick
388053901Smckusick if (sdc->sdc_wticks++ >= timeo) {
388153901Smckusick register struct scsi *sc;
388253901Smckusick
388353901Smckusick sc = get_scsi(im->im_intr);
388453901Smckusick sdc->sdc_wticks = 0;
388553901Smckusick printf("sdc%d: lost interrupt\n", i);
388653901Smckusick
388753901Smckusick screset(im->im_intr);
388853901Smckusick }
388953901Smckusick }
389053901Smckusick }
389153901Smckusick
389253901Smckusick /*
389353901Smckusick * sdstop() is timer interrupt routine.
389453901Smckusick * So, can't use sleep().
389553901Smckusick */
sdstop()389653901Smckusick sdstop()
389753901Smckusick {
389853901Smckusick register struct iop/**/_ctlr *im;
389953901Smckusick register struct iop/**/_device *ii;
390053901Smckusick register struct sdc_softc *sdc;
390153901Smckusick register struct sdd_softc *sdd;
390253901Smckusick register int unit;
390353901Smckusick register int intr;
390453901Smckusick register int i;
390553901Smckusick struct scsi *sc;
390653901Smckusick int eject_sw;
390753901Smckusick
390853901Smckusick timeout(sdstop, (caddr_t)0, hz);
390953901Smckusick
391053901Smckusick for (i = 0; i < nsdc; i++) {
391153901Smckusick im = sdminfo[i];
391253901Smckusick if (im == 0)
391353901Smckusick continue;
391453901Smckusick if (im->im_alive == 0)
391553901Smckusick continue;
391653901Smckusick for (unit = 0; unit < nsd; unit++) {
391753901Smckusick if ((ii = sddinfo[unit]) == 0)
391853901Smckusick continue;
391953901Smckusick if (ii->ii_mi != im)
392053901Smckusick continue;
392153901Smckusick sdc = &sdc_softc[ii->ii_ctlr];
392253901Smckusick if ((sdc->sdc_firmware & SDCFW_RMB) == 0)
392353901Smckusick continue;
392453901Smckusick intr = ii->ii_intr;
392553901Smckusick if (isalone(unit))
392653901Smckusick continue;
392753901Smckusick /**********************/
392853901Smckusick /* MO & CD-ROM */
392953901Smckusick /**********************/
393053901Smckusick /*
393153901Smckusick * there is no process which open the unit.
393253901Smckusick */
393353901Smckusick sdd = &sdd_softc[unit];
393453901Smckusick sc = get_scsi(intr);
393553901Smckusick if (sdd->sdd_start > 0)
393653901Smckusick sdd->sdd_start--;
393753901Smckusick else if (sdd->sdd_start == 0) {
393853901Smckusick /*
393953901Smckusick * Now stop the unit.
394053901Smckusick * check SCSI access
394153901Smckusick */
394253901Smckusick if (sdc->sdc_firmware & SDCFW_BUSY)
394353901Smckusick continue;
394453901Smckusick sdc->sdc_firmware |= SDCFW_BUSY;
394553901Smckusick sdc->sdc_state |= SDCS_IOCTL|SDCS_SCUNLOCK;
394653901Smckusick
394753901Smckusick eject_sw = (sdd->sdd_flags & SDDF_REQ_EJECT) ?
394853901Smckusick SDSS_EJECT : SDSS_STOP;
394953901Smckusick scop_stst(intr, sc, ii->ii_slave,
395053901Smckusick SCSI_INTEN, eject_sw);
395153901Smckusick sdd->sdd_start = -2;
395253901Smckusick }
395353901Smckusick }
395453901Smckusick }
395553901Smckusick }
395653901Smckusick
isalone(unit)395753901Smckusick isalone(unit)
395853901Smckusick register int unit;
395953901Smckusick {
396053901Smckusick register int i, n;
396153901Smckusick
396253901Smckusick n = 0;
396353901Smckusick for (i = 0; i < PNUM; i++)
396453901Smckusick n += (sd_b_openf[unit][i] + sd_c_openf[unit][i]);
396553901Smckusick return (n);
396653901Smckusick }
396753901Smckusick
396853901Smckusick /************************************************
396953901Smckusick * Convert Hex and RS code table definition *
397053901Smckusick ************************************************/
397153901Smckusick
397253901Smckusick #define X8_L 0x001d
397353901Smckusick #define X8_H 0x1d00
397453901Smckusick
397553901Smckusick
397653901Smckusick #define hextors(data) hxtable[(int)((data) & 0xff)]
397753901Smckusick #define XORMASK(code) xortable[(unsigned int)(code)]
397853901Smckusick
397953901Smckusick int hxtable[256] = {
398053901Smckusick 0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6,
398153901Smckusick 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
398253901Smckusick 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
398353901Smckusick 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
398453901Smckusick 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21,
398553901Smckusick 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
398653901Smckusick 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9,
398753901Smckusick 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
398853901Smckusick 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
398953901Smckusick 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
399053901Smckusick 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd,
399153901Smckusick 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
399253901Smckusick 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e,
399353901Smckusick 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
399453901Smckusick 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
399553901Smckusick 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
399653901Smckusick 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d,
399753901Smckusick 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
399853901Smckusick 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c,
399953901Smckusick 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
400053901Smckusick 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
400153901Smckusick 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
400253901Smckusick 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e,
400353901Smckusick 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
400453901Smckusick 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76,
400553901Smckusick 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
400653901Smckusick 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
400753901Smckusick 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
400853901Smckusick 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51,
400953901Smckusick 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
401053901Smckusick 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8,
401153901Smckusick 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf,
401253901Smckusick };
401353901Smckusick
401453901Smckusick int xortable[256] = {
401553901Smckusick 0x00000000, 0x90910101, 0x91210201, 0x01b00300,
401653901Smckusick 0x92410401, 0x02d00500, 0x03600600, 0x93f10701,
401753901Smckusick 0x94810801, 0x04100900, 0x05a00a00, 0x95310b01,
401853901Smckusick 0x06c00c00, 0x96510d01, 0x97e10e01, 0x07700f00,
401953901Smckusick 0x99011001, 0x09901100, 0x08201200, 0x98b11301,
402053901Smckusick 0x0b401400, 0x9bd11501, 0x9a611601, 0x0af01700,
402153901Smckusick 0x0d801800, 0x9d111901, 0x9ca11a01, 0x0c301b00,
402253901Smckusick 0x9fc11c01, 0x0f501d00, 0x0ee01e00, 0x9e711f01,
402353901Smckusick 0x82012001, 0x12902100, 0x13202200, 0x83b12301,
402453901Smckusick 0x10402400, 0x80d12501, 0x81612601, 0x11f02700,
402553901Smckusick 0x16802800, 0x86112901, 0x87a12a01, 0x17302b00,
402653901Smckusick 0x84c12c01, 0x14502d00, 0x15e02e00, 0x85712f01,
402753901Smckusick 0x1b003000, 0x8b913101, 0x8a213201, 0x1ab03300,
402853901Smckusick 0x89413401, 0x19d03500, 0x18603600, 0x88f13701,
402953901Smckusick 0x8f813801, 0x1f103900, 0x1ea03a00, 0x8e313b01,
403053901Smckusick 0x1dc03c00, 0x8d513d01, 0x8ce13e01, 0x1c703f00,
403153901Smckusick 0xb4014001, 0x24904100, 0x25204200, 0xb5b14301,
403253901Smckusick 0x26404400, 0xb6d14501, 0xb7614601, 0x27f04700,
403353901Smckusick 0x20804800, 0xb0114901, 0xb1a14a01, 0x21304b00,
403453901Smckusick 0xb2c14c01, 0x22504d00, 0x23e04e00, 0xb3714f01,
403553901Smckusick 0x2d005000, 0xbd915101, 0xbc215201, 0x2cb05300,
403653901Smckusick 0xbf415401, 0x2fd05500, 0x2e605600, 0xbef15701,
403753901Smckusick 0xb9815801, 0x29105900, 0x28a05a00, 0xb8315b01,
403853901Smckusick 0x2bc05c00, 0xbb515d01, 0xbae15e01, 0x2a705f00,
403953901Smckusick 0x36006000, 0xa6916101, 0xa7216201, 0x37b06300,
404053901Smckusick 0xa4416401, 0x34d06500, 0x35606600, 0xa5f16701,
404153901Smckusick 0xa2816801, 0x32106900, 0x33a06a00, 0xa3316b01,
404253901Smckusick 0x30c06c00, 0xa0516d01, 0xa1e16e01, 0x31706f00,
404353901Smckusick 0xaf017001, 0x3f907100, 0x3e207200, 0xaeb17301,
404453901Smckusick 0x3d407400, 0xadd17501, 0xac617601, 0x3cf07700,
404553901Smckusick 0x3b807800, 0xab117901, 0xaaa17a01, 0x3a307b00,
404653901Smckusick 0xa9c17c01, 0x39507d00, 0x38e07e00, 0xa8717f01,
404753901Smckusick 0xd8018001, 0x48908100, 0x49208200, 0xd9b18301,
404853901Smckusick 0x4a408400, 0xdad18501, 0xdb618601, 0x4bf08700,
404953901Smckusick 0x4c808800, 0xdc118901, 0xdda18a01, 0x4d308b00,
405053901Smckusick 0xdec18c01, 0x4e508d00, 0x4fe08e00, 0xdf718f01,
405153901Smckusick 0x41009000, 0xd1919101, 0xd0219201, 0x40b09300,
405253901Smckusick 0xd3419401, 0x43d09500, 0x42609600, 0xd2f19701,
405353901Smckusick 0xd5819801, 0x45109900, 0x44a09a00, 0xd4319b01,
405453901Smckusick 0x47c09c00, 0xd7519d01, 0xd6e19e01, 0x46709f00,
405553901Smckusick 0x5a00a000, 0xca91a101, 0xcb21a201, 0x5bb0a300,
405653901Smckusick 0xc841a401, 0x58d0a500, 0x5960a600, 0xc9f1a701,
405753901Smckusick 0xce81a801, 0x5e10a900, 0x5fa0aa00, 0xcf31ab01,
405853901Smckusick 0x5cc0ac00, 0xcc51ad01, 0xcde1ae01, 0x5d70af00,
405953901Smckusick 0xc301b001, 0x5390b100, 0x5220b200, 0xc2b1b301,
406053901Smckusick 0x5140b400, 0xc1d1b501, 0xc061b601, 0x50f0b700,
406153901Smckusick 0x5780b800, 0xc711b901, 0xc6a1ba01, 0x5630bb00,
406253901Smckusick 0xc5c1bc01, 0x5550bd00, 0x54e0be00, 0xc471bf01,
406353901Smckusick 0x6c00c000, 0xfc91c101, 0xfd21c201, 0x6db0c300,
406453901Smckusick 0xfe41c401, 0x6ed0c500, 0x6f60c600, 0xfff1c701,
406553901Smckusick 0xf881c801, 0x6810c900, 0x69a0ca00, 0xf931cb01,
406653901Smckusick 0x6ac0cc00, 0xfa51cd01, 0xfbe1ce01, 0x6b70cf00,
406753901Smckusick 0xf501d001, 0x6590d100, 0x6420d200, 0xf4b1d301,
406853901Smckusick 0x6740d400, 0xf7d1d501, 0xf661d601, 0x66f0d700,
406953901Smckusick 0x6180d800, 0xf111d901, 0xf0a1da01, 0x6030db00,
407053901Smckusick 0xf3c1dc01, 0x6350dd00, 0x62e0de00, 0xf271df01,
407153901Smckusick 0xee01e001, 0x7e90e100, 0x7f20e200, 0xefb1e301,
407253901Smckusick 0x7c40e400, 0xecd1e501, 0xed61e601, 0x7df0e700,
407353901Smckusick 0x7a80e800, 0xea11e901, 0xeba1ea01, 0x7b30eb00,
407453901Smckusick 0xe8c1ec01, 0x7850ed00, 0x79e0ee00, 0xe971ef01,
407553901Smckusick 0x7700f000, 0xe791f101, 0xe621f201, 0x76b0f300,
407653901Smckusick 0xe541f401, 0x75d0f500, 0x7460f600, 0xe4f1f701,
407753901Smckusick 0xe381f801, 0x7310f900, 0x72a0fa00, 0xe231fb01,
407853901Smckusick 0x71c0fc00, 0xe151fd01, 0xe0e1fe01, 0x7070ff00
407953901Smckusick };
408053901Smckusick
408153901Smckusick /********************************************************
408253901Smckusick * EDC (Error Detection Code) check *
408353901Smckusick * (using CRC code) *
408453901Smckusick * MODE 1 : Sync + Header + User data + edc *
408553901Smckusick * MODE 2 : Sub header + User data + edc *
408653901Smckusick ********************************************************/
408753901Smckusick
408853901Smckusick #define SYNC_EDC 0x908eff4e /* sector sync EDC value */
408953901Smckusick #define HEADER 4 /* header length 4 bytes */
409053901Smckusick #define SUB_H 8 /* Subheader length 8 bytes */
409153901Smckusick #define USER_DATA 2048 /* User data length 2048 bytes */
409253901Smckusick #define EDC_LEN 4 /* EDC code length 4 bytes */
409353901Smckusick
cal_edc1(db,mode)409453901Smckusick cal_edc1(db, mode)
409553901Smckusick register unsigned char *db;
409653901Smckusick int mode;
409753901Smckusick {
409853901Smckusick register int j;
409953901Smckusick register unsigned int work;
410053901Smckusick
410153901Smckusick j = USER_DATA + EDC_LEN;
410253901Smckusick if (mode == 2) {
410353901Smckusick j += SUB_H;
410453901Smckusick work = 0;
410553901Smckusick } else {
410653901Smckusick j += HEADER;
410753901Smckusick work = SYNC_EDC;
410853901Smckusick }
410953901Smckusick while (--j >= 0)
411053901Smckusick work = ((work >> 8) | (*db++ << 24)) ^ XORMASK(work & 0xff);
411153901Smckusick
411253901Smckusick return (work);
411353901Smckusick }
411453901Smckusick
411553901Smckusick
411653901Smckusick /************************************************/
411753901Smckusick /* error detection & correction */
411853901Smckusick /* if form 1 */
411953901Smckusick /* header area should be zero */
412053901Smckusick /************************************************/
412153901Smckusick
412253901Smckusick /*
412353901Smckusick * error detection & correction P-direction
412453901Smckusick */
p_dir(dbuf)412553901Smckusick p_dir(dbuf)
412653901Smckusick register unsigned short *dbuf;
412753901Smckusick {
412853901Smckusick unsigned short s0, s1, d;
412953901Smckusick register int col, row;
413053901Smckusick register int x;
413153901Smckusick unsigned char s0l, s0h, s1l, s1h;
413253901Smckusick
413353901Smckusick /*
413453901Smckusick * calculate syndrome S0 S1
413553901Smckusick */
413653901Smckusick for (col = 0; col < 43; col++) {
413753901Smckusick s0 = s1 = 0;
413853901Smckusick
413953901Smckusick for (row = 0; row < 26; row++) {
414053901Smckusick d = dbuf[43 * row + col];
414153901Smckusick s0 ^= d;
414253901Smckusick s1 = rsshift(s1) ^ d;
414353901Smckusick }
414453901Smckusick
414553901Smckusick s0h = s0 & 0x00ff;
414653901Smckusick s1h = s1 & 0x00ff;
414753901Smckusick s0l = (s0 >> 8) & 0x00ff;
414853901Smckusick s1l = (s1 >> 8) & 0x00ff;
414953901Smckusick /*
415053901Smckusick * calculate error position & correction
415153901Smckusick */
415253901Smckusick if (s0l != 0) {
415353901Smckusick if((x = hextors(s1l) - hextors(s0l)) < 0)
415453901Smckusick x += 255;
415553901Smckusick if ((x >= 0) && (x < 26)) {
415653901Smckusick x = 25 - x;
415753901Smckusick /*
415853901Smckusick * correction
415953901Smckusick */
416053901Smckusick dbuf[43 * x + col] ^= (s0 & 0xff00);
416153901Smckusick }
416253901Smckusick }
416353901Smckusick
416453901Smckusick /*
416553901Smckusick * calculate error position & correction
416653901Smckusick */
416753901Smckusick if (s0h != 0) {
416853901Smckusick if((x = hextors(s1h) - hextors(s0h)) < 0)
416953901Smckusick x += 255;
417053901Smckusick if ((x >= 0) && (x < 26)) {
417153901Smckusick x = 25 - x;
417253901Smckusick /*
417353901Smckusick * correction
417453901Smckusick */
417553901Smckusick dbuf[43 * x + col] ^= (s0 & 0x00ff);
417653901Smckusick }
417753901Smckusick }
417853901Smckusick }
417953901Smckusick }
418053901Smckusick
418153901Smckusick /*
418253901Smckusick * error detection & correction Q-direction
418353901Smckusick */
q_dir(dbuf)418453901Smckusick q_dir(dbuf)
418553901Smckusick register unsigned short *dbuf;
418653901Smckusick {
418753901Smckusick unsigned short s0, s1, d;
418853901Smckusick register int col, row;
418953901Smckusick register int x;
419053901Smckusick unsigned char s0l, s0h, s1l, s1h;
419153901Smckusick
419253901Smckusick /*
419353901Smckusick * calculate syndrome S0 S1
419453901Smckusick */
419553901Smckusick for (row = 0; row < 26; row++) {
419653901Smckusick s0 = s1 = 0;
419753901Smckusick
419853901Smckusick for (col = 0; col < 45; col++) {
419953901Smckusick if (col < 43)
420053901Smckusick d = dbuf[(44 * col + 43 * row) % 1118];
420153901Smckusick else if (col == 43)
420253901Smckusick d = dbuf[43 * 26 + row];
420353901Smckusick else
420453901Smckusick d = dbuf[44 * 26 + row];
420553901Smckusick s0 ^= d;
420653901Smckusick s1 = rsshift(s1) ^ d;
420753901Smckusick }
420853901Smckusick
420953901Smckusick s0h = s0 & 0x00ff;
421053901Smckusick s1h = s1 & 0x00ff;
421153901Smckusick s0l = (s0 >> 8) & 0x00ff;
421253901Smckusick s1l = (s1 >> 8) & 0x00ff;
421353901Smckusick /*
421453901Smckusick * calculate error position & correction
421553901Smckusick */
421653901Smckusick if (s0l != 0) {
421753901Smckusick if((x = hextors(s1l) - hextors(s0l)) < 0)
421853901Smckusick x += 255;
421953901Smckusick if (x >= 0 && x < 45) {
422053901Smckusick x = 44 - x;
422153901Smckusick /*
422253901Smckusick * correction
422353901Smckusick */
422453901Smckusick if (x < 43)
422553901Smckusick dbuf[(44 * x + 43 * row) % 1118]
422653901Smckusick ^= s0 & 0xff00;
422753901Smckusick else if (x == 43)
422853901Smckusick dbuf[43 * 26 + row] ^= s0 & 0xff00;
422953901Smckusick else
423053901Smckusick dbuf[44 * 26 + row] ^= s0 & 0xff00;
423153901Smckusick }
423253901Smckusick }
423353901Smckusick
423453901Smckusick /*
423553901Smckusick * calculate error position & correction
423653901Smckusick */
423753901Smckusick if (s0h != 0) {
423853901Smckusick if((x = hextors(s1h) - hextors(s0h)) < 0)
423953901Smckusick x += 255;
424053901Smckusick if ((x >= 0) && (x < 45)) {
424153901Smckusick x = 44 - x;
424253901Smckusick /*
424353901Smckusick * correction
424453901Smckusick */
424553901Smckusick if (x < 43)
424653901Smckusick dbuf[(44 * x + 43 * row) % 1118]
424753901Smckusick ^= s0 & 0x00ff;
424853901Smckusick else if ( x == 43)
424953901Smckusick dbuf[43 * 26 + row] ^= s0 & 0x00ff;
425053901Smckusick else
425153901Smckusick dbuf[44 * 26 + row] ^= s0 & 0x00ff;
425253901Smckusick }
425353901Smckusick }
425453901Smckusick }
425553901Smckusick }
425653901Smckusick
425753901Smckusick /*
425853901Smckusick * shift high & low byte at the same time
425953901Smckusick */
rsshift(d)426053901Smckusick rsshift(d)
426153901Smckusick unsigned short d;
426253901Smckusick {
426353901Smckusick register int x;
426453901Smckusick register int dmy; /* This way is faster */
426553901Smckusick
426653901Smckusick dmy = (int)d;
426753901Smckusick x = (dmy << 1) & 0xfefe; /* clear LSB of high & low byte */
426853901Smckusick if ((dmy & 0x0080) != 0)
426953901Smckusick x ^= X8_L;
427053901Smckusick if ((dmy & 0x8000) != 0)
427153901Smckusick x ^= X8_H;
427253901Smckusick return(x);
427353901Smckusick }
427453901Smckusick #endif /* NSD > 0 */
4275