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