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 2008 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 * 512; 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 unsigned char bufaddr[2048]; 217 int status; 218 219 status = ata_rdwr(DIR_READ, cur_file, (diskaddr_t)1, 4, 220 (caddr_t)bufaddr, 0, NULL); 221 222 return (!status); 223 } 224 225 226 #if defined(i386) 227 228 static int 229 get_alts_slice() 230 { 231 232 int i; 233 int alts_slice = -1; 234 235 if (cur_parts == NULL) { 236 (void) fprintf(stderr, "No current partition list\n"); 237 return (-1); 238 } 239 240 for (i = 0; i < V_NUMPAR && alts_slice == -1; i++) { 241 if (cur_parts->vtoc.v_part[i].p_tag == V_ALTSCTR) { 242 alts_slice = i; 243 dpart = &cur_parts->vtoc.v_part[i]; 244 } 245 } 246 247 if (alts_slice == -1) { 248 (void) fprintf(stderr, "NO Alt slice\n"); 249 return (-1); 250 } 251 if (!solaris_offset) 252 if (copy_solaris_part(&cur_disk->fdisk_part)) 253 return (-1); 254 255 altsec_offset = dpart->p_start + solaris_offset; 256 257 return (SUCCESS); 258 } 259 260 261 static int 262 put_alts_slice() 263 { 264 int status; 265 266 status = wr_altsctr(); 267 if (status) { 268 return (status); 269 } 270 271 if (ioctl(cur_file, DKIOCADDBAD, NULL) == -1) { 272 (void) fprintf(stderr, "Warning: DKIOCADDBAD ioctl failed\n"); 273 sync(); 274 return (-1); 275 } 276 sync(); 277 return (0); 278 } 279 280 static int 281 ata_convert_list(struct defect_list *list, int list_format) 282 { 283 284 int i; 285 struct defect_entry *new_defect; 286 287 switch (list_format) { 288 289 case BFI_FORMAT: 290 if (ap->ap_tblp->alts_ent_used) { 291 new_defect = calloc(ap->ap_tblp->alts_ent_used, 292 sizeof (struct defect_entry)); 293 if (new_defect == NULL) { 294 err_print( 295 "ata_convert_list: calloc failed\n"); 296 fullabort(); 297 } 298 list->header.count = ap->ap_tblp->alts_ent_used; 299 list->header.magicno = (uint_t)DEFECT_MAGIC; 300 list->list = new_defect; 301 for (i = 0; i < ap->ap_tblp->alts_ent_used; 302 i++, new_defect++) { 303 new_defect->cyl = 304 bn2c((ap->ap_entp)[i].bad_start); 305 new_defect->head = 306 bn2h((ap->ap_entp)[i].bad_start); 307 new_defect->bfi = UNKNOWN; 308 new_defect->sect = 309 bn2s((ap->ap_entp)[i].bad_start); 310 new_defect->nbits = UNKNOWN; 311 } 312 313 314 } else { 315 316 list->header.count = 0; 317 list->header.magicno = (uint_t)DEFECT_MAGIC; 318 new_defect = calloc(1, 319 sizeof (struct defect_entry)); 320 if (new_defect == NULL) { 321 err_print( 322 "ata_convert_list: calloc failed\n"); 323 fullabort(); 324 } 325 list->list = new_defect; 326 } 327 break; 328 329 default: 330 err_print("ata_convert_list: can't deal with it\n"); 331 exit(0); 332 } 333 (void) checkdefsum(list, CK_MAKESUM); 334 return (0); 335 } 336 337 338 /* 339 * NB - there used to be a ata_ex_man() which was identical to 340 * ata_ex_cur; since it's really not a "manufacturer's list", 341 * it's gone; if we ever want that exact functionality back, 342 * we can add ata_ex_cur() to the ctlr_ops above. Otherwise, 343 * if this is ever modified to support formatting of IDE drives, 344 * we should probably add something that issues the 345 * drive Read Defect list rather than getting the s9 info 346 * as ata_ex_cur() does. 347 */ 348 349 static int 350 ata_ex_cur(struct defect_list *list) 351 { 352 int status; 353 354 status = get_alts_slice(); 355 if (status) 356 return (status); 357 status = read_altsctr(dpart); 358 if (status) { 359 return (status); 360 } 361 (void) ata_convert_list(list, BFI_FORMAT); 362 return (status); 363 } 364 365 int 366 ata_repair(diskaddr_t bn, int flag) 367 { 368 369 int status; 370 struct badsec_lst *blc_p; 371 struct badsec_lst *blc_p_nxt; 372 373 #ifdef lint 374 flag++; 375 #endif 376 377 (void) get_alts_slice(); 378 if (!gbadsl_chain) { 379 blc_p = (struct badsec_lst *)calloc(1, BADSLSZ); 380 if (!blc_p) { 381 (void) fprintf(stderr, 382 "Unable to allocate memory for additional bad sectors\n"); 383 return (-1); 384 } 385 gbadsl_chain = blc_p; 386 } 387 for (blc_p = gbadsl_chain; blc_p->bl_nxt; ) 388 blc_p = blc_p->bl_nxt; 389 390 if (blc_p->bl_cnt == MAXBLENT) { 391 blc_p->bl_nxt = (struct badsec_lst *)calloc(1, BADSLSZ); 392 if (!blc_p->bl_nxt) { 393 (void) fprintf(stderr, 394 "Unable to allocate memory for additional bad sectors\n"); 395 return (-1); 396 } 397 blc_p = blc_p->bl_nxt; 398 } 399 blc_p->bl_sec[blc_p->bl_cnt++] = (uint_t)bn; 400 gbadsl_chain_cnt++; 401 402 (void) updatebadsec(dpart, 0); 403 status = put_alts_slice(); 404 405 /* clear out the bad sector list chains that were generated */ 406 407 if (badsl_chain) { 408 if (badsl_chain->bl_nxt == NULL) { 409 free(badsl_chain); 410 } else { 411 for (blc_p = badsl_chain; blc_p; ) { 412 blc_p_nxt = blc_p->bl_nxt; 413 free(blc_p); 414 blc_p = blc_p_nxt; 415 } 416 } 417 badsl_chain = NULL; 418 badsl_chain_cnt = 0; 419 } 420 421 if (gbadsl_chain) { 422 if (gbadsl_chain->bl_nxt == NULL) { 423 free(gbadsl_chain); 424 } else { 425 for (blc_p = gbadsl_chain; blc_p; ) { 426 blc_p_nxt = blc_p->bl_nxt; 427 free(blc_p); 428 blc_p = blc_p_nxt; 429 } 430 } 431 gbadsl_chain = NULL; 432 gbadsl_chain_cnt = 0; 433 } 434 435 return (status); 436 437 } 438 439 int 440 ata_wr_cur(struct defect_list *list) 441 { 442 int status; 443 int sec_count; 444 int x; 445 struct badsec_lst *blc_p; 446 struct badsec_lst *blc_p_nxt; 447 struct defect_entry *dlist; 448 449 if (list->header.magicno != (uint_t)DEFECT_MAGIC) 450 return (-1); 451 452 sec_count = list->header.count; 453 dlist = list->list; 454 455 (void) get_alts_slice(); 456 for (x = 0; x < sec_count; x++) { 457 458 /* test for unsupported list format */ 459 if ((dlist->bfi != UNKNOWN) || (dlist->nbits != UNKNOWN)) { 460 (void) fprintf(stderr, 461 "BFI unsuported format for bad sectors\n"); 462 return (-1); 463 } 464 465 if (!gbadsl_chain) { 466 blc_p = (struct badsec_lst *)calloc(1, BADSLSZ); 467 if (!blc_p) { 468 (void) fprintf(stderr, 469 "Unable to allocate memory for additional bad sectors\n"); 470 return (-1); 471 } 472 gbadsl_chain = blc_p; 473 } 474 475 for (blc_p = gbadsl_chain; blc_p->bl_nxt; ) 476 blc_p = blc_p->bl_nxt; 477 478 if (blc_p->bl_cnt == MAXBLENT) { 479 blc_p->bl_nxt = (struct badsec_lst *)calloc(1, BADSLSZ); 480 if (!blc_p->bl_nxt) { 481 (void) fprintf(stderr, 482 "Unable to allocate memory for additional bad sectors\n"); 483 return (-1); 484 } 485 blc_p = blc_p->bl_nxt; 486 } 487 blc_p->bl_sec[blc_p->bl_cnt++] = 488 (uint_t)chs2bn(dlist->cyl, dlist->head, dlist->sect); 489 gbadsl_chain_cnt++; 490 dlist++; 491 } 492 493 494 (void) updatebadsec(dpart, 0); 495 status = put_alts_slice(); 496 497 /* clear out the bad sector list chains that were generated */ 498 499 if (badsl_chain) { 500 if (badsl_chain->bl_nxt == NULL) { 501 free(badsl_chain); 502 } else { 503 for (blc_p = badsl_chain; blc_p; ) { 504 blc_p_nxt = blc_p->bl_nxt; 505 free(blc_p); 506 blc_p = blc_p_nxt; 507 } 508 } 509 badsl_chain = NULL; 510 badsl_chain_cnt = 0; 511 } 512 513 if (gbadsl_chain) { 514 if (gbadsl_chain->bl_nxt == NULL) { 515 free(gbadsl_chain); 516 } else { 517 for (blc_p = gbadsl_chain; blc_p; ) { 518 blc_p_nxt = blc_p->bl_nxt; 519 free(blc_p); 520 blc_p = blc_p_nxt; 521 } 522 } 523 gbadsl_chain = NULL; 524 gbadsl_chain_cnt = 0; 525 } 526 527 return (status); 528 } 529 530 #endif /* defined(i386) */ 531