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