* Copyright (c) 1988 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)hd.c 7.6 (Berkeley) 5/1/89
#include "../tahoe/mtpr.h"
#include "../tahoevba/hdreg.h"
static struct registers
*hdc_regs
[HDC_MAXCTLR
][HDC_MAXBUS
];
static struct disklabel dklabel
[HDC_MAXDRIVE
][HDC_MAXCTLR
][HDC_MAXBUS
];
register struct disklabel
*dlp
;
long junk
, dlbuf
[DEV_BSIZE
/sizeof(long)];
/* validate the device specification */
if ((u_int
)io
->i_bus
>= HDC_MAXBUS
)
if ((u_int
)io
->i_ctlr
>= HDC_MAXCTLR
)
if ((u_int
)io
->i_unit
>= HDC_MAXDRIVE
)
if ((u_int
)io
->i_part
> 7)
/* init drive structure. */
hdc_regs
[io
->i_ctlr
][io
->i_bus
] = hr
= (struct registers
*)(io
->i_bus
?
0x80000000 | io
->i_ctlr
<< 24 | HDC_MID
<< 16 :
0xC0000000 | io
->i_ctlr
<< 24 | HDC_MID
<< 16);
/* insure that this is an hdc, then reset the hdc. */
if (wbadaddr(&hr
->module_id
, 4, &junk
)) {
printf("hd%d: %x: invalid csr\n", io
->i_ctlr
, (u_int
)hr
);
* read in the hdc module id word. The controller is bad if the
* hdc's writeable control store is not loaded or if the hdc failed
* the functional integrity test for any reason.
hr
->module_id
= (u_long
)&id
;
if (id
.module_id
!= (u_char
)HDC_MID
) {
printf("hdc: controller bad module id: id = %x\n",
if (id
.code_rev
== (u_char
)0xff) {
printf("hdc: controller micro-code is not loaded.\n");
if (id
.fit
!= (u_char
)0xff) {
printf("hdc: controller FIT test failed: error= %x\n",
/* read the drive status */
mcb
.command
= HCMD_STATUS
;
mcb
.chain
[0].wcount
= (long)(sizeof(struct status
) / sizeof(long));
mcb
.chain
[0].memadr
= (long)&status
;
* Report drive down if anything in the drive status is bad.
* If fault condition, reading will try to clear the fault.
if (status
.drs
&DRS_FAULT
)
printf("hdc: clearing drive fault.\n");
if (!(status
.drs
&DRS_ONLINE
)) {
printf("hdc: drive is not online.\n");
/* read in the pack label */
mcb
.sector
= LABELSECTOR
;
mcb
.chain
[0].wcount
= (long)(DEV_BSIZE
/ sizeof(long));
mcb
.chain
[0].memadr
= (long)dlbuf
;
dlp
= (struct disklabel
*)(dlbuf
+ (LABELOFFSET
/ sizeof(long)));
if (dlp
->d_magic
!= DISKMAGIC
|| dlp
->d_magic2
!= DISKMAGIC
)
if (error
= hdmaptype(io
, dlp
, &status
, io
->i_unit
))
dklabel
[io
->i_unit
][io
->i_ctlr
][io
->i_bus
] = *dlp
;
if (io
->i_part
>= dlp
->d_npartitions
||
dlp
->d_partitions
[io
->i_part
].p_size
== 0)
io
->i_boff
= (dlp
->d_partitions
[io
->i_part
].p_offset
*
dlp
->d_secsize
) / DEV_BSIZE
;
register struct disklabel
*dlp
;
printf("hd%d: i/o not a longword multiple.\n", io
->i_unit
);
dlp
= &dklabel
[io
->i_unit
][io
->i_ctlr
][io
->i_bus
];
sector
= io
->i_bn
* HDC_SPB
;
mcb
.command
= (cmd
== READ
) ? HCMD_READ
: HCMD_WRITE
;
mcb
.cyl
= sector
/ dlp
->d_secpercyl
;
mcb
.head
= (sector
/ dlp
->d_nsectors
) % dlp
->d_ntracks
;
mcb
.sector
= sector
% dlp
->d_nsectors
;
mcb
.chain
[0].wcount
= io
->i_cc
/ sizeof(long);
mcb
.chain
[0].memadr
= (u_long
)io
->i_ma
;
return(hdimcb(&mcb
, io
) ? -1 : io
->i_cc
);
register struct mcb
*mcb
;
struct master_mcb master
;
master
.mcw
= MCL_IMMEDIATE
;
master
.forw_phaddr
= (u_long
)mcb
;
hdc_regs
[io
->i_ctlr
][io
->i_bus
]->master_mcb
= (u_long
)&master
;
for (timeout
= 15000; timeout
; --timeout
) {
if (master
.mcs
&MCS_FATALERROR
) {
printf("hdc%d: fatal error.\n", io
->i_ctlr
);
printf("hdc%d: timed out.\n", io
->i_ctlr
);
hdmaptype(io
, dlp
, status
, unit
)
register struct disklabel
*dlp
;
geometry_sector geometry
;
printf("hd%d: unlabeled\n", unit
);
* Read the geometry block (at head = 0 sector = 0 of the drive
* definition cylinder), validate it (must have the correct version
* number, header, and checksum).
mcb
.cyl
= status
->def_cyl
;
mcb
.chain
[0].wcount
= (long)(sizeof(geometry_sector
) / sizeof(long));
mcb
.chain
[0].memadr
= (long)&geometry
;
printf("hd%d: can't read default geometry.\n", io
->i_unit
);
geo
= &geometry
.geometry_block
;
if (geo
->version
> 64000 || geo
->version
< 0) {
printf("hd%d: bad default geometry version#.\n", io
->i_unit
);
if (strcmp(&geo
->id
[0], GB_ID
)) {
printf("hd%d: bad default geometry header.\n", io
->i_unit
);
if (geometry
.checksum
!= cnt
) {
printf("hd%d: bad default geometry checksum.\n", io
->i_unit
);
for (cnt
= 0; cnt
< GB_MAXPART
; cnt
++) {
dlp
->d_partitions
[cnt
].p_offset
= geo
->partition
[cnt
].start
;
dlp
->d_partitions
[cnt
].p_size
= geo
->partition
[cnt
].length
;
dlp
->d_secsize
= status
->bytes_per_sec
;
dlp
->d_nsectors
= status
->max_sector
+ 1;
dlp
->d_ncylinders
= status
->max_cyl
+ 1;
dlp
->d_ntracks
= status
->max_head
+ 1;
dlp
->d_secpercyl
= dlp
->d_ntracks
* dlp
->d_nsectors
;
dlp
->d_npartitions
= GB_MAXPART
;
dlp
->d_rpm
= status
->rpm
;
(void)strcpy(dlp
->d_typename
, "hdc (prom)");