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
ata_rdwr(int dir,int fd,diskaddr_t blk64,int secnt,caddr_t bufaddr,int flags,int * xfercntp)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
ata_ck_format(void)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
get_alts_slice(void)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
put_alts_slice(void)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
ata_convert_list(struct defect_list * list,int list_format)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
ata_ex_cur(struct defect_list * list)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
ata_repair(diskaddr_t bn,int flag)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
ata_wr_cur(struct defect_list * list)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