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