640 number_to_scaled_string is duplicated in several commands
[unleashed.git] / usr / src / cmd / format / ctlr_ata.c
blobc8f982d71bbaa4bf316aaecafe955521adb9a489
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file contains the routines for the IDE drive interface
29 #include "global.h"
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>
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"
57 #include "menu_fdisk.h"
59 int wr_altsctr();
60 int read_altsctr();
61 int updatebadsec();
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
79 struct ctlr_ops ataops = {
80 #if defined(sparc)
81 ata_rdwr,
82 ata_ck_format,
89 #else
90 ata_rdwr,
91 ata_ck_format,
94 ata_ex_cur,
95 ata_repair,
97 ata_wr_cur,
98 #endif /* defined(sparc) */
101 struct ctlr_ops pcmcia_ataops = {
102 ata_rdwr,
103 ata_ck_format,
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;
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 */
140 /*ARGSUSED6*/
141 #if defined(i386)
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) */
151 int tmpsec;
152 struct dadkio_rwcmd dadkio_rwcmd;
153 blkaddr_t blkno;
155 blkno = (blkaddr_t)blk64;
156 bzero((caddr_t)&dadkio_rwcmd, sizeof (struct dadkio_rwcmd));
158 tmpsec = secnt * cur_blksz;
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;
168 media_error = 0;
169 if (cur_ctype->ctype_ctype == DKC_PCMCIA_ATA) {
171 * PCATA requires to use "p0" when calling
172 * DIOCTL_RWCMD ioctl() to read/write the label
174 (void) close(fd);
175 (void) open_cur_file(FD_USE_P0_PATH);
176 fd = cur_file;
179 if (ioctl(fd, DIOCTL_RWCMD, &dadkio_rwcmd) == -1) {
180 err_print("DIOCTL_RWCMD: %s\n", strerror(errno));
181 return (1);
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);
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;
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);
210 return (0);
214 ata_ck_format()
216 char *bufaddr;
217 int status;
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);
223 free(bufaddr);
225 return (!status);
229 #if defined(i386)
231 static int
232 get_alts_slice()
235 int i;
236 int alts_slice = -1;
238 if (cur_parts == NULL) {
239 (void) fprintf(stderr, "No current partition list\n");
240 return (-1);
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];
250 if (alts_slice == -1) {
251 (void) fprintf(stderr, "NO Alt slice\n");
252 return (-1);
254 if (!solaris_offset)
255 if (copy_solaris_part(&cur_disk->fdisk_part))
256 return (-1);
258 altsec_offset = dpart->p_start + solaris_offset;
260 return (SUCCESS);
264 static int
265 put_alts_slice()
267 int status;
269 status = wr_altsctr();
270 if (status) {
271 return (status);
274 if (ioctl(cur_file, DKIOCADDBAD, NULL) == -1) {
275 (void) fprintf(stderr, "Warning: DKIOCADDBAD ioctl failed\n");
276 sync();
277 return (-1);
279 sync();
280 return (0);
283 static int
284 ata_convert_list(struct defect_list *list, int list_format)
287 int i;
288 struct defect_entry *new_defect;
290 switch (list_format) {
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();
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;
317 } else {
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();
328 list->list = new_defect;
330 break;
332 default:
333 err_print("ata_convert_list: can't deal with it\n");
334 exit(0);
336 (void) checkdefsum(list, CK_MAKESUM);
337 return (0);
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.
352 static int
353 ata_ex_cur(struct defect_list *list)
355 int status;
357 status = get_alts_slice();
358 if (status)
359 return (status);
360 status = read_altsctr(dpart);
361 if (status) {
362 return (status);
364 (void) ata_convert_list(list, BFI_FORMAT);
365 return (status);
369 ata_repair(diskaddr_t bn, int flag)
372 int status;
373 struct badsec_lst *blc_p;
374 struct badsec_lst *blc_p_nxt;
376 #ifdef lint
377 flag++;
378 #endif
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);
388 gbadsl_chain = blc_p;
390 for (blc_p = gbadsl_chain; blc_p->bl_nxt; )
391 blc_p = blc_p->bl_nxt;
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);
400 blc_p = blc_p->bl_nxt;
402 blc_p->bl_sec[blc_p->bl_cnt++] = (uint_t)bn;
403 gbadsl_chain_cnt++;
405 (void) updatebadsec(dpart, 0);
406 status = put_alts_slice();
408 /* clear out the bad sector list chains that were generated */
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;
420 badsl_chain = NULL;
421 badsl_chain_cnt = 0;
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;
434 gbadsl_chain = NULL;
435 gbadsl_chain_cnt = 0;
438 return (status);
443 ata_wr_cur(struct defect_list *list)
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;
452 if (list->header.magicno != (uint_t)DEFECT_MAGIC)
453 return (-1);
455 sec_count = list->header.count;
456 dlist = list->list;
458 (void) get_alts_slice();
459 for (x = 0; x < sec_count; x++) {
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);
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);
475 gbadsl_chain = blc_p;
478 for (blc_p = gbadsl_chain; blc_p->bl_nxt; )
479 blc_p = blc_p->bl_nxt;
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);
488 blc_p = blc_p->bl_nxt;
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++;
497 (void) updatebadsec(dpart, 0);
498 status = put_alts_slice();
500 /* clear out the bad sector list chains that were generated */
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;
512 badsl_chain = NULL;
513 badsl_chain_cnt = 0;
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;
526 gbadsl_chain = NULL;
527 gbadsl_chain_cnt = 0;
530 return (status);
533 #endif /* defined(i386) */