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