#include "global.h"
#include <sys/types.h>
#include <sys/param.h>
#if defined(sparc)
#include <sys/hdio.h>
#endif
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <string.h>
#include <unistd.h>
#include <memory.h>
#if defined(sparc)
#include <sys/dkbad.h>
#endif
#include "misc.h"
#include "param.h"
#if defined(sparc)
struct dkbad badmap;
#endif
void
read_list(struct defect_list *list)
{
int size, head;
#if defined(sparc)
int sec, status;
struct bt_bad *bt;
#endif
assert(!EMBEDDED_SCSI);
if (cur_ctype->ctype_flags & CF_NOWLIST) {
return;
}
if (cur_ctype->ctype_flags & CF_WLIST) {
if (*cur_ops->op_ex_cur != NULL &&
((*cur_ops->op_ex_cur)(list)) == 0) {
if (list->header.magicno != DEFECT_MAGIC) {
fmt_print("Defect list BAD\n");
} else {
fmt_print("Controller working list found\n");
}
return;
}
if (*cur_ops->op_ex_man != NULL &&
((*cur_ops->op_ex_man)(list)) == 0) {
if (list->header.magicno != DEFECT_MAGIC) {
fmt_print("Defect list BAD\n");
} else {
fmt_print("MANUFACTURER's list found\n");
}
return;
}
fmt_print("No defect list found\n");
return;
}
for (head = 0; head < LISTCOUNT; head++) {
if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
(diskaddr_t)chs2bn(ncyl + 1, head, 0), 1,
(char *)&list->header, NULL), F_NORMAL)
continue;
if (list->header.magicno != DEFECT_MAGIC)
continue;
size = deflist_size(cur_blksz, list->header.count);
list->list = (struct defect_entry *)zalloc(size * cur_blksz);
if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
(diskaddr_t)chs2bn(ncyl + 1, head, 1), size,
(char *)list->list, F_NORMAL, NULL) ||
checkdefsum(list, CK_CHECKSUM)) {
kill_deflist(list);
continue;
}
break;
}
#if defined(sparc)
if (!(cur_ctlr->ctlr_flags & DKI_BAD144))
return;
for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) {
status = (*cur_ops->op_rdwr)(DIR_READ, cur_file,
(diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1,
&badmap, F_NORMAL, NULL);
if (status)
continue;
if (badmap.bt_mbz != 0)
continue;
for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++) {
if (bt->bt_cyl < 0)
break;
if (bt->bt_trksec < 0)
continue;
head = bt->bt_trksec >> 8;
if ((bt->bt_cyl >= pcyl) || (head >= nhead) ||
((bt->bt_trksec & 0xff) >= sectors(head))) {
status = -1;
break;
}
}
if (status)
continue;
return;
}
for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++)
bt->bt_cyl = bt->bt_trksec = -1;
badmap.bt_mbz = badmap.bt_csn = badmap.bt_flag = 0;
#endif
}
int
checkdefsum(struct defect_list *list, int mode)
{
register int *lp, i, sum = 0;
lp = (int *)list->list;
for (i = 0; i < (list->header.count *
sizeof (struct defect_entry) / sizeof (int)); i++)
sum ^= *(lp + i);
if (mode == CK_CHECKSUM)
return (sum != list->header.cksum);
else {
list->header.cksum = sum;
return (0);
}
}
void
pr_defect(struct defect_entry *def, int num)
{
++num;
fmt_print("%4d%8d%7d", num, def->cyl, def->head);
if (def->bfi != UNKNOWN) {
fmt_print("%8d", def->bfi);
if (def->nbits != UNKNOWN)
fmt_print("%8d", def->nbits);
} else {
fmt_print(" ");
fmt_print("%8d", def->sect);
fmt_print("%8llu", chs2bn(def->cyl, def->head, def->sect));
}
fmt_print("\n");
}
int
sort_defect(struct defect_entry *def, struct defect_list *list)
{
struct defect_entry *ptr;
if (def->bfi == UNKNOWN)
return (list->header.count);
for (ptr = list->list; ptr - list->list < list->header.count; ptr++) {
if (ptr->bfi == UNKNOWN)
goto found;
if (def->cyl < ptr->cyl)
goto found;
if (def->cyl != ptr->cyl)
continue;
if (def->head < ptr->head)
goto found;
if (def->head != ptr->head)
continue;
if (def->bfi < ptr->bfi)
goto found;
}
found:
return (ptr - list->list);
}
void
write_deflist(struct defect_list *list)
{
int size, head, status;
#if defined(sparc)
int sec;
caddr_t bad_ptr = (caddr_t)&badmap;
#endif
assert(!EMBEDDED_SCSI);
if (cur_ctype->ctype_flags & CF_NOWLIST) {
return;
}
if (cur_ctype->ctype_flags & CF_WLIST) {
(*cur_ops->op_wr_cur)(list);
return;
}
if (list->list != NULL) {
size = deflist_size(cur_blksz, list->header.count);
for (head = 0; head < LISTCOUNT; head++) {
status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
(diskaddr_t)chs2bn(ncyl + 1, head, 0), 1,
(char *)&list->header, F_NORMAL, NULL);
if (status) {
err_print(
"Warning: error saving defect list.\n");
continue;
}
status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
(diskaddr_t)chs2bn(ncyl + 1, head, 1), size,
(char *)list->list, F_NORMAL, NULL);
if (status)
err_print(
"Warning: error saving defect list.\n");
}
}
if (!(cur_ctlr->ctlr_flags & DKI_BAD144))
return;
#if defined(sparc)
for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) {
status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
(diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1,
&badmap, F_NORMAL, NULL);
if (status) {
err_print(
"Warning: error saving bad block map table.\n");
continue;
}
}
if (ioctl(cur_file, HDKIOCSBAD, &bad_ptr))
err_print(
"Warning: error telling SunOS bad block map table.\n");
#endif
}
void
add_ldef(diskaddr_t blkno, struct defect_list *list)
{
struct defect_entry def;
int index;
def.cyl = bn2c(blkno);
def.head = bn2h(blkno);
def.sect = bn2s(blkno);
def.bfi = def.nbits = UNKNOWN;
index = sort_defect(&def, list);
add_def(&def, list, index);
}
void
add_def(struct defect_entry *def, struct defect_list *list, int index)
{
int count, i;
count = list->header.count;
if (deflist_size(cur_blksz, count + 1) > deflist_size(cur_blksz, count))
list->list = (struct defect_entry *)rezalloc((void *)list->list,
deflist_size(cur_blksz, count + 1) * cur_blksz);
for (i = count; i > index; i--)
*(list->list + i) = *(list->list + i - 1);
*(list->list + i) = *def;
list->header.count++;
(void) checkdefsum(list, CK_MAKESUM);
}
void
kill_deflist(struct defect_list *list)
{
if (list->list == NULL)
return;
destroy_data((char *)list->list);
list->list = NULL;
list->flags = 0;
}
int
deflist_size(int secsz, int sz)
{
int rval;
if (secsz == 0) {
secsz = SECSIZE;
}
rval = sz ? ((sz * sizeof (struct defect_entry) +
secsz - 1) / secsz) : 1;
return (rval);
}