Home | History | Annotate | Download | only in format
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * This file contains the routines for the IDE drive interface
     28  */
     29 #include "global.h"
     30 
     31 #include <sys/types.h>
     32 #include <sys/param.h>
     33 #include <sys/ioctl.h>
     34 #include <sys/uio.h>
     35 #include <sys/fcntl.h>
     36 #include <memory.h>
     37 #include <malloc.h>
     38 #include <unistd.h>
     39 #include <stdlib.h>
     40 #include <string.h>
     41 #include <sys/byteorder.h>
     42 #include <errno.h>
     43 #if defined(i386)
     44 #include <sys/dktp/altsctr.h>
     45 #endif
     46 #include <sys/dktp/dadkio.h>
     47 
     48 
     49 #include "startup.h"
     50 #include "misc.h"
     51 #include "ctlr_ata.h"
     52 #include "analyze.h"
     53 #include "param.h"
     54 #include "io.h"
     55 #include "badsec.h"
     56 
     57 #include "menu_fdisk.h"
     58 
     59 int	wr_altsctr();
     60 int	read_altsctr();
     61 int	updatebadsec();
     62 
     63 #ifdef  __STDC__
     64 static int	ata_ck_format(void);
     65 #ifdef i386
     66 static int	ata_ex_cur(struct defect_list *);
     67 static int	ata_wr_cur(struct defect_list *);
     68 static int	ata_repair(diskaddr_t, int);
     69 #endif /* i386 */
     70 #else /* __STDC__ */
     71 static int	ata_ck_format();
     72 #ifdef i386
     73 static int	ata_ex_cur();
     74 static int	ata_wr_cur();
     75 static int	ata_repair();
     76 #endif /* i386 */
     77 #endif
     78 
     79 struct  ctlr_ops ataops = {
     80 #if defined(sparc)
     81 	ata_rdwr,
     82 	ata_ck_format,
     83 	0,
     84 	0,
     85 	0,
     86 	0,
     87 	0,
     88 	0,
     89 #else
     90 	ata_rdwr,
     91 	ata_ck_format,
     92 	0,
     93 	0,
     94 	ata_ex_cur,
     95 	ata_repair,
     96 	0,
     97 	ata_wr_cur,
     98 #endif	/* defined(sparc) */
     99 };
    100 
    101 struct  ctlr_ops pcmcia_ataops = {
    102 	ata_rdwr,
    103 	ata_ck_format,
    104 	0,
    105 	0,
    106 	0,
    107 	0,
    108 	0,
    109 	0,
    110 };
    111 
    112 
    113 #if defined(i386)
    114 static struct	dkl_partition	*dpart = NULL;
    115 #endif	/* defined(i386) */
    116 extern	struct	badsec_lst	*badsl_chain;
    117 extern	int	badsl_chain_cnt;
    118 extern	struct	badsec_lst	*gbadsl_chain;
    119 extern	int	gbadsl_chain_cnt;
    120 extern	struct	alts_mempart	*ap;
    121 
    122 static char *dadkrawioerrs[] = {
    123 	"cmd was successful",		/* DADKIO_STAT_NO_ERROR */
    124 	"device not ready",		/* DADKIO_STAT_NOT_READY */
    125 	"error on medium blkno: %d",	/* DADKIO_STAT_MEDIUM_ERROR */
    126 	"other hardware error",		/* DADKIO_STAT_HARDWARE_ERROR */
    127 	"illegal request",		/* DADKIO_STAT_ILLEGAL_REQUEST */
    128 	"illegal block address: %d",	/* DADKIO_STAT_ILLEGAL_ADDRESS */
    129 	"device write-protected",	/* DADKIO_STAT_WRITE_PROTECTED	*/
    130 	"no response from device",	/* DADKIO_STAT_TIMED_OUT */
    131 	"parity error in data",		/* DADKIO_STAT_PARITY */
    132 	"error on bus",			/* DADKIO_STAT_BUS_ERROR */
    133 	"data recovered via ECC",	/* DADKIO_STAT_SOFT_ERROR */
    134 	"no resources for cmd",		/* DADKIO_STAT_NO_RESOURCES */
    135 	"device is not formatted",	/* DADKIO_STAT_NOT_FORMATTED */
    136 	"device is reserved",		/* DADKIO_STAT_RESERVED */
    137 	"feature not supported",	/* DADKIO_STAT_NOT_SUPPORTED */
    138 	};
    139 
    140 /*ARGSUSED6*/
    141 #if	defined(i386)
    142 int
    143 ata_rdwr(int dir, int fd, diskaddr_t blk64, int secnt, caddr_t bufaddr,
    144 		int flags, int *xfercntp)
    145 #else	/* defined(i386) */
    146 static int
    147 ata_rdwr(int dir, int fd, diskaddr_t blk64, int secnt, caddr_t bufaddr,
    148 		int flags, int *xfercntp)
    149 #endif	/* defined(i386) */
    150 {
    151 	int	tmpsec;
    152 	struct dadkio_rwcmd	dadkio_rwcmd;
    153 	blkaddr_t	blkno;
    154 
    155 	blkno = (blkaddr_t)blk64;
    156 	bzero((caddr_t)&dadkio_rwcmd, sizeof (struct dadkio_rwcmd));
    157 
    158 	tmpsec = secnt * cur_blksz;
    159 
    160 	/* Doing raw read */
    161 	dadkio_rwcmd.cmd = (dir == DIR_READ) ? DADKIO_RWCMD_READ :
    162 					DADKIO_RWCMD_WRITE;
    163 	dadkio_rwcmd.blkaddr = blkno;
    164 	dadkio_rwcmd.buflen  = tmpsec;
    165 	dadkio_rwcmd.flags   = flags;
    166 	dadkio_rwcmd.bufaddr = bufaddr;
    167 
    168 	media_error = 0;
    169 	if (cur_ctype->ctype_ctype == DKC_PCMCIA_ATA) {
    170 		/*
    171 		 * PCATA requires to use "p0" when calling
    172 		 *	DIOCTL_RWCMD ioctl() to read/write the label
    173 		 */
    174 		(void) close(fd);
    175 		(void) open_cur_file(FD_USE_P0_PATH);
    176 		fd = cur_file;
    177 	}
    178 
    179 	if (ioctl(fd, DIOCTL_RWCMD, &dadkio_rwcmd) == -1) {
    180 		err_print("DIOCTL_RWCMD: %s\n", strerror(errno));
    181 		return (1);
    182 	}
    183 
    184 	if (cur_ctype->ctype_ctype == DKC_PCMCIA_ATA) {
    185 		/* Restore cur_file with cur_disk->disk_path */
    186 		(void) open_cur_file(FD_USE_CUR_DISK_PATH);
    187 	}
    188 
    189 	switch (dadkio_rwcmd.status.status) {
    190 	case  DADKIO_STAT_NOT_READY:
    191 			disk_error = DISK_STAT_NOTREADY;
    192 			break;
    193 	case  DADKIO_STAT_RESERVED:
    194 			disk_error = DISK_STAT_RESERVED;
    195 			break;
    196 	case  DADKIO_STAT_WRITE_PROTECTED:
    197 			disk_error = DISK_STAT_DATA_PROTECT;
    198 			break;
    199 	case DADKIO_STAT_MEDIUM_ERROR:
    200 			media_error = 1;
    201 			break;
    202 	}
    203 
    204 	if (dadkio_rwcmd.status.status) {
    205 		if ((flags & F_SILENT) == 0)
    206 			err_print(dadkrawioerrs[dadkio_rwcmd.status.status],
    207 				dadkio_rwcmd.status.failed_blk);
    208 		return (1);
    209 	}
    210 	return (0);
    211 }
    212 
    213 int
    214 ata_ck_format()
    215 {
    216 	char *bufaddr;
    217 	int status;
    218 
    219 	bufaddr = (char *)zalloc(4 * cur_blksz);
    220 	status = ata_rdwr(DIR_READ, cur_file, (diskaddr_t)1, 4,
    221 	    (caddr_t)bufaddr, 0, NULL);
    222 
    223 	free(bufaddr);
    224 
    225 	return (!status);
    226 }
    227 
    228 
    229 #if defined(i386)
    230 
    231 static int
    232 get_alts_slice()
    233 {
    234 
    235 	int	i;
    236 	int	alts_slice = -1;
    237 
    238 	if (cur_parts == NULL) {
    239 		(void) fprintf(stderr, "No current partition list\n");
    240 		return (-1);
    241 	}
    242 
    243 	for (i = 0; i < V_NUMPAR && alts_slice == -1; i++) {
    244 		if (cur_parts->vtoc.v_part[i].p_tag == V_ALTSCTR) {
    245 			alts_slice = i;
    246 			dpart = &cur_parts->vtoc.v_part[i];
    247 		}
    248 	}
    249 
    250 	if (alts_slice == -1) {
    251 		(void) fprintf(stderr, "NO Alt slice\n");
    252 		return (-1);
    253 	}
    254 	if (!solaris_offset)
    255 		if (copy_solaris_part(&cur_disk->fdisk_part))
    256 			return (-1);
    257 
    258 	altsec_offset = dpart->p_start + solaris_offset;
    259 
    260 	return (SUCCESS);
    261 }
    262 
    263 
    264 static int
    265 put_alts_slice()
    266 {
    267 	int	status;
    268 
    269 	status = wr_altsctr();
    270 	if (status) {
    271 		return (status);
    272 	}
    273 
    274 	if (ioctl(cur_file, DKIOCADDBAD, NULL) == -1) {
    275 		(void) fprintf(stderr, "Warning: DKIOCADDBAD ioctl failed\n");
    276 		sync();
    277 		return (-1);
    278 	}
    279 	sync();
    280 	return (0);
    281 }
    282 
    283 static int
    284 ata_convert_list(struct defect_list *list, int list_format)
    285 {
    286 
    287 	int	i;
    288 	struct  defect_entry    *new_defect;
    289 
    290 	switch (list_format) {
    291 
    292 	case BFI_FORMAT:
    293 		if (ap->ap_tblp->alts_ent_used) {
    294 			new_defect = calloc(ap->ap_tblp->alts_ent_used,
    295 			    sizeof (struct defect_entry));
    296 			if (new_defect == NULL) {
    297 				err_print(
    298 				    "ata_convert_list: calloc failed\n");
    299 				fullabort();
    300 			}
    301 			list->header.count = ap->ap_tblp->alts_ent_used;
    302 			list->header.magicno = (uint_t)DEFECT_MAGIC;
    303 			list->list = new_defect;
    304 			for (i = 0; i < ap->ap_tblp->alts_ent_used;
    305 			    i++, new_defect++) {
    306 				new_defect->cyl =
    307 				    bn2c((ap->ap_entp)[i].bad_start);
    308 				new_defect->head =
    309 				    bn2h((ap->ap_entp)[i].bad_start);
    310 				new_defect->bfi = UNKNOWN;
    311 				new_defect->sect =
    312 				    bn2s((ap->ap_entp)[i].bad_start);
    313 				new_defect->nbits = UNKNOWN;
    314 			}
    315 
    316 
    317 		} else {
    318 
    319 			list->header.count = 0;
    320 			list->header.magicno = (uint_t)DEFECT_MAGIC;
    321 			new_defect = calloc(1,
    322 			    sizeof (struct defect_entry));
    323 			if (new_defect == NULL) {
    324 				err_print(
    325 				    "ata_convert_list: calloc failed\n");
    326 				fullabort();
    327 			}
    328 			list->list = new_defect;
    329 		}
    330 		break;
    331 
    332 	default:
    333 		err_print("ata_convert_list: can't deal with it\n");
    334 		exit(0);
    335 	}
    336 	(void) checkdefsum(list, CK_MAKESUM);
    337 	return (0);
    338 }
    339 
    340 
    341 /*
    342  * NB - there used to be a ata_ex_man() which was identical to
    343  * ata_ex_cur; since it's really not a "manufacturer's list",
    344  * it's gone; if we ever want that exact functionality back,
    345  * we can add ata_ex_cur() to the ctlr_ops above.  Otherwise,
    346  * if this is ever modified to support formatting of IDE drives,
    347  * we should probably add something that issues the
    348  * drive Read Defect list rather than getting the s9 info
    349  * as ata_ex_cur() does.
    350  */
    351 
    352 static int
    353 ata_ex_cur(struct defect_list *list)
    354 {
    355 	int	status;
    356 
    357 	status = get_alts_slice();
    358 	if (status)
    359 		return (status);
    360 	status = read_altsctr(dpart);
    361 	if (status) {
    362 		return (status);
    363 	}
    364 	(void) ata_convert_list(list, BFI_FORMAT);
    365 	return (status);
    366 }
    367 
    368 int
    369 ata_repair(diskaddr_t bn, int flag)
    370 {
    371 
    372 	int	status;
    373 	struct	badsec_lst	*blc_p;
    374 	struct	badsec_lst	*blc_p_nxt;
    375 
    376 #ifdef lint
    377 	flag++;
    378 #endif
    379 
    380 	(void) get_alts_slice();
    381 	if (!gbadsl_chain) {
    382 		blc_p = (struct badsec_lst *)calloc(1, BADSLSZ);
    383 		if (!blc_p) {
    384 			(void) fprintf(stderr,
    385 		"Unable to allocate memory for additional bad sectors\n");
    386 			return (-1);
    387 		}
    388 		gbadsl_chain = blc_p;
    389 	}
    390 	for (blc_p = gbadsl_chain; blc_p->bl_nxt; )
    391 		blc_p = blc_p->bl_nxt;
    392 
    393 	if (blc_p->bl_cnt == MAXBLENT) {
    394 		blc_p->bl_nxt = (struct badsec_lst *)calloc(1, BADSLSZ);
    395 		if (!blc_p->bl_nxt) {
    396 			(void) fprintf(stderr,
    397 		"Unable to allocate memory for additional bad sectors\n");
    398 			return (-1);
    399 		}
    400 		blc_p = blc_p->bl_nxt;
    401 	}
    402 	blc_p->bl_sec[blc_p->bl_cnt++] = (uint_t)bn;
    403 	gbadsl_chain_cnt++;
    404 
    405 	(void) updatebadsec(dpart, 0);
    406 	status = put_alts_slice();
    407 
    408 	/* clear out the bad sector list chains that were generated */
    409 
    410 	if (badsl_chain) {
    411 		if (badsl_chain->bl_nxt == NULL) {
    412 			free(badsl_chain);
    413 		} else {
    414 			for (blc_p = badsl_chain; blc_p; ) {
    415 				blc_p_nxt = blc_p->bl_nxt;
    416 				free(blc_p);
    417 				blc_p = blc_p_nxt;
    418 			}
    419 		}
    420 		badsl_chain = NULL;
    421 		badsl_chain_cnt = 0;
    422 	}
    423 
    424 	if (gbadsl_chain) {
    425 		if (gbadsl_chain->bl_nxt == NULL) {
    426 			free(gbadsl_chain);
    427 		} else {
    428 			for (blc_p = gbadsl_chain; blc_p; ) {
    429 				blc_p_nxt = blc_p->bl_nxt;
    430 				free(blc_p);
    431 				blc_p = blc_p_nxt;
    432 			}
    433 		}
    434 		gbadsl_chain = NULL;
    435 		gbadsl_chain_cnt = 0;
    436 	}
    437 
    438 	return (status);
    439 
    440 }
    441 
    442 int
    443 ata_wr_cur(struct defect_list *list)
    444 {
    445 	int	status;
    446 	int	sec_count;
    447 	int	x;
    448 	struct	badsec_lst	*blc_p;
    449 	struct	badsec_lst	*blc_p_nxt;
    450 	struct	defect_entry	*dlist;
    451 
    452 	if (list->header.magicno != (uint_t)DEFECT_MAGIC)
    453 		return (-1);
    454 
    455 	sec_count = list->header.count;
    456 	dlist = list->list;
    457 
    458 	(void) get_alts_slice();
    459 	for (x = 0; x < sec_count; x++) {
    460 
    461 		/* test for unsupported list format */
    462 		if ((dlist->bfi != UNKNOWN) || (dlist->nbits != UNKNOWN)) {
    463 			(void) fprintf(stderr,
    464 			    "BFI unsuported format for bad sectors\n");
    465 			return (-1);
    466 		}
    467 
    468 		if (!gbadsl_chain) {
    469 			blc_p = (struct badsec_lst *)calloc(1, BADSLSZ);
    470 			if (!blc_p) {
    471 				(void) fprintf(stderr,
    472 		"Unable to allocate memory for additional bad sectors\n");
    473 				return (-1);
    474 			}
    475 			gbadsl_chain = blc_p;
    476 		}
    477 
    478 		for (blc_p = gbadsl_chain; blc_p->bl_nxt; )
    479 			blc_p = blc_p->bl_nxt;
    480 
    481 		if (blc_p->bl_cnt == MAXBLENT) {
    482 			blc_p->bl_nxt = (struct badsec_lst *)calloc(1, BADSLSZ);
    483 			if (!blc_p->bl_nxt) {
    484 				(void) fprintf(stderr,
    485 		"Unable to allocate memory for additional bad sectors\n");
    486 				return (-1);
    487 			}
    488 			blc_p = blc_p->bl_nxt;
    489 		}
    490 		blc_p->bl_sec[blc_p->bl_cnt++] =
    491 		    (uint_t)chs2bn(dlist->cyl, dlist->head, dlist->sect);
    492 		gbadsl_chain_cnt++;
    493 		dlist++;
    494 	}
    495 
    496 
    497 	(void) updatebadsec(dpart, 0);
    498 	status = put_alts_slice();
    499 
    500 	/* clear out the bad sector list chains that were generated */
    501 
    502 	if (badsl_chain) {
    503 		if (badsl_chain->bl_nxt == NULL) {
    504 			free(badsl_chain);
    505 		} else {
    506 			for (blc_p = badsl_chain; blc_p; ) {
    507 				blc_p_nxt = blc_p->bl_nxt;
    508 				free(blc_p);
    509 				blc_p = blc_p_nxt;
    510 			}
    511 		}
    512 		badsl_chain = NULL;
    513 		badsl_chain_cnt = 0;
    514 	}
    515 
    516 	if (gbadsl_chain) {
    517 		if (gbadsl_chain->bl_nxt == NULL) {
    518 			free(gbadsl_chain);
    519 		} else {
    520 			for (blc_p = gbadsl_chain; blc_p; ) {
    521 				blc_p_nxt = blc_p->bl_nxt;
    522 				free(blc_p);
    523 				blc_p = blc_p_nxt;
    524 			}
    525 		}
    526 		gbadsl_chain = NULL;
    527 		gbadsl_chain_cnt = 0;
    528 	}
    529 
    530 	return (status);
    531 }
    532 
    533 #endif	/*  defined(i386)  */
    534