'\"macro stdmacro
.if n .pH ddi_dki.hdeeqd @(#)hdeeqd	40.8 of 10/10/89
.\" Copyright 1989 AT&T
.de IX
.ie '\\n(.z'' .tm .Index: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9	\\n%
.el \\!.IX \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
..
.nr X
.if \nX=0 .ds x} hdeeqd D3D "3B2" "DDI" "\&"
.if \nX=1 .ds x} hdeeqd D3D "3B2" "DDI"
.if \nX=2 .ds x} hdeeqd D3D "" "\&"
.if \nX=3 .ds x} hdeeqd "" "" "\&"
.TH \*(x}
.IX "\f4hdeeqd\fP(D3D)"
.SH NAME 
\f4hdeeqd\f1 \- initialize hard disk error logging
.SH "SYNOPSIS" 
.nf
.na
\f4#include <sys/types.h>
#include <sys/hdelog.h>
#include <sys/mkdev.h>
.sp 0.5
int hdeeqd(o_dev_t \f2dev, \f4daddr_t \f2pdsno, \f4short \f2edtyp\f4);\f1
.ad
.fi
.SH "ARGUMENTS" 
.RS 0n 10
.IP "\f2dev\f1" 10n
External device number (contains both the major number and the minor number).
The driver must call the \f4cmpdev\f1 macro (defined in \f4mkdev.h\fP) to compress the device
number.
.IP "\f2pdsno\f1" 10n
Physical description sector
.IP "\f2edtyp\f1" 10n
Error device type.  The valid values are
.P
.RS 16
.TP 12
\f4EQD_EFC\f1
external floppy controller
.PD 0
.TP
\f4EQD_EHDC\f1
external hard disk controller
.TP
\f4EQD_ID\f1
integral disk drive
.TP
\f4EQD_IF\f1
integral floppy disk drive
.TP
\f4EQD_TAPE\f1
cartridge tape drive
.PD
.RE
.RE
.SH "DESCRIPTION" 
\f4hdeeqd\f1 initializes information in the hard disk error logging table for
the device specified by \f2dev\f1.
This function is called once per device.
.P
\f3NOTE:\f1
This function is not part of the default set of kernel
functions.  Ensure that the \f4HDE\f1 bootable object module is placed
in the \f4/boot\f1 directory.
.SH "RETURN VALUE" 
Under all conditions, a \f40\f1 is returned.
However, internal errors can
occur in \f4hdeeqd\f1 causing a warning message to display on the
console.
Errors occur in the following conditions:
.IP "" 6n
The internal major device number is greater than or equal to the number of the
controllers, called \f4cdevcnt\f1, which is assigned by \f4lboot\f1 when
the operating system is loaded.  The message is
.P
.RS 8
.nf
.na
\f4WARNING: hdeeqd: major(ddev) = \f2int-major\f4 (>=cdevcnt)\f1
.fi
.ad
.RE
.IP "" 6n
\f2int-major\f1 is the internal major device number.
.IP
The count of used disk slots in the error logging table exceeds the number of
available slots.  The message is
.P
.RS 8
.nf
.na
\f4WARNING:  Too few HDE equipped slots
bad block handling skipped for maj/min = \f2ext-maj, ext-min\f1
.ad
.fi
.RE
.IP "" 6n
\f2ext-maj\f1 and \f2ext-min\f1 are the external major and minor numbers.
.SH LEVEL 
Base or Interrupt
.SH "SEE ALSO" 
\f2BCI Driver Development Guide\f1, Chapter 12, ``Error Reporting''
.P
.na
\f4hdelog\f1(D3D),
\f4hdedata\f1(D4D)
.ad
.SH EXAMPLE 
.IX "\f4hdedata\fP(D4D), example"
.IX "\f4hdeeqd\fP(D3D), example"
.IX "\f4getminor\fP(D3DK), example"
.P
When a device is opened for the first time, the driver \f4open\f1(D2DK)
or \f4init\f1(D2D) routines (\f4open\f1 in this example) must
identify the device and set up controlling information about the device.  In
this example, the information is kept on a controlling sector on the disk.  If
the controlling sector does not exist, the information is encoded as a
\f4static\f1 table in the driver.
.ne 4
.P
.nf
.ft 4
.ps 7
 1   #define XX_CNTLBLKNO   0      /* controlling sector block number   */
 2   struct  device {              /* physical device registers layout  */
 3           char      reserve[4]; /* reserve space on card             */
 4           ushort    control;    /* physical device control word      */
 5           char      status;     /* physical device status word       */
 6           char      ivec_num;   /* device interrupt vector number in */
 7                                 /* 0xf0; subdevice reporting in 0x0f */
 8           paddr_t   addr;       /* data address to be read/written   */
 9           int       count;      /* amount of data to be read/written */
10  }; /* end device */
11  struct xx_     {                  /* logical device structure       */
12           struct buf    *xx_head;  /* I/O buffer queue head pointer  */
13           struct buf    *xx_tail;  /* I/O buffer queue tail pointer  */
14           short          xx_flag;  /* logical status flag            */
15           struct hdedata xx_edata; /* disk error log error record    */
16           struct iostat  xx_stat;  /* unit I/O statistics for        */
17                   /* establishing an error rate during error logging */
18  }; /* end xx_ */
19
20  struct xx_info   {                /* information on control sector  */
21           long    xx_id;           /* disk device id code            */
22           long    xx_cyl;          /* total number of cylinders      */
23           long    xx_trk;          /* number of tracks per cylinder  */
24           long    xx_sec;          /* number of sectors per track    */
25           char    xx_serial[12];   /* device serial number           */
26  }; /* end xx_info */
27
28  extern struct xx_   xx_devtab[]; /* logical device structures table */
29  extern struct device *xx_addr[]; /* physical dev registers location */
30  extern struct xx_info xx_info[];  /* device control information     */
31  extern int            xx_cnt;     /* number of devices              */
      . . .
32  xx_open(dev, flag, otyp, crp)
33          dev_t   *dev;
34          int       flag, otype;
35          struct cred *crp;
36  {
37      register struct xx_     *dp;
38      register struct device  *rp;
39      register int unit;
           . . .
40      unit = getminor(dev) >> 4;            /* get drive unit number */
41      dp   = &xx_devtab[unit];      /* get logical device information */
42  if  ((dp->xx_flag & XX_OPEN) == 0) { /* if first time device opened */
43      register struct buf *bp;
44      hdeeqd(cmpdev(dev), XX_CNTLBLKNO, EQD_ID); /* initialize error logging  */
45      bp = kmem_alloc(1024, KM_NOSLEEP); /* get control sector buffer */
46      bp->b_flags = B_READ;                  /* set up buffer to read */
47      bp->b_blkno = XX_CNTLBLKNO;         /* control sector from disk */
48      bp->b_count = 512;
49      bp->b_dev = dev;
50      xx_strategy(bp);                         /* read control sector */
51      biowait(bp);                       /* wait for read to complete */
52      if  ((bp->b_flags & B_ERROR) != 0 )  {
53                /* if data error occurred, display message on console */
54          xx_print(dev, "xx_open: cannot read control sector");
55      } else {              /* copy control sector data to info table */
56          bcopy(bp->b_un.b_addr, &xx_info[unit], sizeof(struct xx_info));
57          hdeeqd(cmpdev(dev), XX_CNTLBLKNO, EQD_ID);   /* start error logging */
58          dp->flag |= XX_OPEN;          /* indicate device open       */
59      } /* endif */
60      brelse(bp);                       /* release system buffer      */
61  } /* endif */
.ps
.ft 1
.fi
.P
.FG "hdeeqd \- initialize hard disk error logging"
.P
\f1If this is the first open,
\f4hdeeqd\f1 (line 44) is used to initiate error logging for the device.
A system buffer is allocated (line 45) and the driver
reads the controlling sector from the \f4xx_strategy\f1 routine (line
50).  If an error occurred on the read attempt, an
error message is displayed (line 54) and an error condition is
returned.
Otherwise, the driver saves information from the controlling sector with
\f4bcopy\f1 (line 56) and indicates the device has been opened.
Finally, the system buffer is released (line 60).
