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 routines that manipulate the defect list.
28 */
29 #include "global.h"
30 #include <sys/types.h>
31 #include <sys/param.h>
32
33 #if defined(sparc)
34 #include <sys/hdio.h>
35 #endif /* defined(sparc) */
36
37 #include <sys/buf.h>
38 #include <sys/ioctl.h>
39 #include <sys/uio.h>
40 #include <sys/fcntl.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <memory.h>
44
45 #if defined(sparc)
46 #include <sys/dkbad.h>
47 #endif /* defined(sparc) */
48
49 #include "misc.h"
50 #include "param.h"
51
52
53 #if defined(sparc)
54 /*
55 * This structure is the bad block table for the current disk if
56 * the disk uses bad-144 defect mapping.
57 */
58 struct dkbad badmap;
59 #endif /* defined(sparc) */
60
61 /*
62 * This routine reads the defect list off the disk. It also reads in the
63 * bad block table if the disk is a BAD144 type. The defect list is
64 * located on the first 2 tracks of the 2nd alternate cylinder of all
65 * disks. The bad block map is located on the first 5 even sectors of
66 * the last track of the last cylinder.
67 */
68 void
read_list(struct defect_list * list)69 read_list(struct defect_list *list)
70 {
71 int size, head;
72
73 #if defined(sparc)
74 int sec, status;
75 struct bt_bad *bt;
76 #endif /* defined(sparc) */
77
78 assert(!EMBEDDED_SCSI);
79
80 /*
81 * This flags has been introduced only for Sparc ATA IDE.
82 * This indicates that no list manipulation is done in this controller
83 * and hence return without any other checking.
84 */
85 if (cur_ctype->ctype_flags & CF_NOWLIST) {
86 return;
87 }
88
89 /*
90 * Panther's working list is maintained by the controller
91 */
92 if (cur_ctype->ctype_flags & CF_WLIST) {
93 if (*cur_ops->op_ex_cur != NULL &&
94 ((*cur_ops->op_ex_cur)(list)) == 0) {
95 if (list->header.magicno != DEFECT_MAGIC) {
96 fmt_print("Defect list BAD\n");
97 } else {
98 fmt_print("Controller working list found\n");
99 }
100 return;
101 }
102
103 if (*cur_ops->op_ex_man != NULL &&
104 ((*cur_ops->op_ex_man)(list)) == 0) {
105 if (list->header.magicno != DEFECT_MAGIC) {
106 fmt_print("Defect list BAD\n");
107 } else {
108 fmt_print("MANUFACTURER's list found\n");
109 }
110 return;
111 }
112 fmt_print("No defect list found\n");
113 return;
114 }
115
116 /*
117 * Loop for each copy of the defect list until we get a good one.
118 */
119 for (head = 0; head < LISTCOUNT; head++) {
120 /*
121 * Try to read the list header.
122 */
123 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
124 (diskaddr_t)chs2bn(ncyl + 1, head, 0), 1,
125 (char *)&list->header, NULL), F_NORMAL)
126 continue;
127 /*
128 * If the magic number is wrong, this copy is corrupt.
129 */
130 if (list->header.magicno != DEFECT_MAGIC)
131 continue;
132 /*
133 * Allocate space for the rest of the list.
134 */
135 size = deflist_size(cur_blksz, list->header.count);
136 list->list = (struct defect_entry *)zalloc(size * cur_blksz);
137 /*
138 * Try to read in the rest of the list. If there is an
139 * error, or the checksum is wrong, this copy is corrupt.
140 */
141 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file,
142 (diskaddr_t)chs2bn(ncyl + 1, head, 1), size,
143 (char *)list->list, F_NORMAL, NULL) ||
144 checkdefsum(list, CK_CHECKSUM)) {
145 /*
146 * Destroy the list and go on.
147 */
148 kill_deflist(list);
149 continue;
150 }
151 /*
152 * Got a good copy, stop searching.
153 */
154 break;
155 }
156 #if defined(sparc)
157 if (!(cur_ctlr->ctlr_flags & DKI_BAD144))
158 return;
159 /*
160 * The disk uses BAD144, read in the bad-block table.
161 */
162 for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) {
163 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file,
164 (diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1,
165 &badmap, F_NORMAL, NULL);
166 if (status)
167 continue;
168 /*
169 * Do a sanity check on the list read in. If it passes,
170 * stop searching.
171 */
172 if (badmap.bt_mbz != 0)
173 continue;
174 for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++) {
175 if (bt->bt_cyl < 0)
176 break;
177 if (bt->bt_trksec < 0)
178 continue;
179 head = bt->bt_trksec >> 8;
180 if ((bt->bt_cyl >= pcyl) || (head >= nhead) ||
181 ((bt->bt_trksec & 0xff) >= sectors(head))) {
182 status = -1;
183 break;
184 }
185 }
186 if (status)
187 continue;
188 return;
189 }
190 /*
191 * If we couldn't find the bad block table, initialize it to
192 * zero entries.
193 */
194 for (bt = badmap.bt_bad; bt - badmap.bt_bad < NDKBAD; bt++)
195 bt->bt_cyl = bt->bt_trksec = -1;
196 badmap.bt_mbz = badmap.bt_csn = badmap.bt_flag = 0;
197 #endif /* defined(sparc) */
198 }
199
200 /*
201 * This routine either checks or calculates the checksum for a defect
202 * list, depending on the mode parameter. In check mode, it returns
203 * whether or not the checksum is correct.
204 */
205 int
checkdefsum(struct defect_list * list,int mode)206 checkdefsum(struct defect_list *list, int mode)
207 {
208 register int *lp, i, sum = 0;
209
210 /*
211 * Perform the rolling xor to get what the checksum should be.
212 */
213 lp = (int *)list->list;
214 for (i = 0; i < (list->header.count *
215 sizeof (struct defect_entry) / sizeof (int)); i++)
216 sum ^= *(lp + i);
217 /*
218 * If in check mode, return whether header checksum was correct.
219 */
220 if (mode == CK_CHECKSUM)
221 return (sum != list->header.cksum);
222 /*
223 * If in create mode, set the header checksum.
224 */
225 else {
226 list->header.cksum = sum;
227 return (0);
228 }
229 }
230
231 /*
232 * This routine prints a single defect to stdout in a readable format.
233 */
234 void
pr_defect(struct defect_entry * def,int num)235 pr_defect(struct defect_entry *def, int num)
236 {
237
238 /*
239 * Make defect numbering look 1 relative.
240 */
241 ++num;
242 /*
243 * Print out common values.
244 */
245 fmt_print("%4d%8d%7d", num, def->cyl, def->head);
246 /*
247 * The rest of the values may be unknown. If they are, just
248 * print blanks instead. Also, only print length only if bfi is
249 * known, and assume that a known bfi implies an unknown sect.
250 */
251 if (def->bfi != UNKNOWN) {
252 fmt_print("%8d", def->bfi);
253 if (def->nbits != UNKNOWN)
254 fmt_print("%8d", def->nbits);
255 } else {
256 fmt_print(" ");
257 fmt_print("%8d", def->sect);
258 fmt_print("%8llu", chs2bn(def->cyl, def->head, def->sect));
259 }
260 fmt_print("\n");
261 }
262
263 /*
264 * This routine calculates where in a defect list a given defect should
265 * be sorted. It returns the index that the defect should become. The
266 * algorithm used sorts all bfi based defects by cylinder/head/bfi, and
267 * adds all logical sector defects to the end of the list. This is
268 * necessary because the ordering of logical sector defects is significant
269 * when sector slipping is employed.
270 */
271 int
sort_defect(struct defect_entry * def,struct defect_list * list)272 sort_defect(struct defect_entry *def, struct defect_list *list)
273 {
274 struct defect_entry *ptr;
275
276 /*
277 * If it's a logical sector defect, return the entry at the end
278 * of the list.
279 */
280 if (def->bfi == UNKNOWN)
281 return (list->header.count);
282 /*
283 * It's a bfi defect. Loop through the defect list.
284 */
285 for (ptr = list->list; ptr - list->list < list->header.count; ptr++) {
286 /*
287 * If we get to a logical sector defect, put this defect
288 * right before it.
289 */
290 if (ptr->bfi == UNKNOWN)
291 goto found;
292 /*
293 * If we get to a defect that is past this one in
294 * cylinder/head/bfi, put this defect right before it.
295 */
296 if (def->cyl < ptr->cyl)
297 goto found;
298 if (def->cyl != ptr->cyl)
299 continue;
300 if (def->head < ptr->head)
301 goto found;
302 if (def->head != ptr->head)
303 continue;
304 if (def->bfi < ptr->bfi)
305 goto found;
306 }
307 found:
308 /*
309 * Return the index to put the defect at.
310 */
311 return (ptr - list->list);
312 }
313
314 /*
315 * This routine writes the defect list on the back on the disk. It also
316 * writes the bad block table to disk if bad-144 mapping applies to the
317 * current disk.
318 */
319 void
write_deflist(struct defect_list * list)320 write_deflist(struct defect_list *list)
321 {
322 int size, head, status;
323
324 #if defined(sparc)
325 int sec;
326 caddr_t bad_ptr = (caddr_t)&badmap;
327 #endif /* defined(sparc) */
328
329 assert(!EMBEDDED_SCSI);
330
331 /*
332 * Sparc ATA IDE.
333 * This indicates that no list manipulation is done in this controller
334 * and hence return without any other checking.
335 */
336 if (cur_ctype->ctype_flags & CF_NOWLIST) {
337 return;
338 }
339
340 /*
341 * Panther's working list is maintained by the controller
342 */
343 if (cur_ctype->ctype_flags & CF_WLIST) {
344 (*cur_ops->op_wr_cur)(list);
345 return;
346 }
347
348 /*
349 * If the list is null, there is nothing to write.
350 */
351 if (list->list != NULL) {
352 /*
353 * calculate how many sectors the defect list will occupy.
354 */
355 size = deflist_size(cur_blksz, list->header.count);
356 /*
357 * Loop for each copy of the list to be written. Write
358 * out the header of the list followed by the data.
359 */
360 for (head = 0; head < LISTCOUNT; head++) {
361 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
362 (diskaddr_t)chs2bn(ncyl + 1, head, 0), 1,
363 (char *)&list->header, F_NORMAL, NULL);
364 if (status) {
365 err_print(
366 "Warning: error saving defect list.\n");
367 continue;
368 }
369 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
370 (diskaddr_t)chs2bn(ncyl + 1, head, 1), size,
371 (char *)list->list, F_NORMAL, NULL);
372 if (status)
373 err_print(
374 "Warning: error saving defect list.\n");
375 }
376 }
377 if (!(cur_ctlr->ctlr_flags & DKI_BAD144))
378 return;
379 #if defined(sparc)
380 /*
381 * Current disk uses bad-144 mapping. Loop for each copy of the
382 * bad block table to be written and write it out.
383 */
384 for (sec = 0; ((sec < BAD_LISTCNT * 2) && (sec < nsect)); sec += 2) {
385 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file,
386 (diskaddr_t)chs2bn(ncyl + acyl - 1, nhead - 1, sec), 1,
387 &badmap, F_NORMAL, NULL);
388 if (status) {
389 err_print(
390 "Warning: error saving bad block map table.\n");
391 continue;
392 }
393 }
394 /*
395 * Execute an ioctl to tell unix about the new bad block table.
396 */
397 if (ioctl(cur_file, HDKIOCSBAD, &bad_ptr))
398 err_print(
399 "Warning: error telling SunOS bad block map table.\n");
400 #endif /* defined(sparc) */
401 }
402
403 /*
404 * This routine adds a logical sector to the given defect list.
405 */
406 void
add_ldef(diskaddr_t blkno,struct defect_list * list)407 add_ldef(diskaddr_t blkno, struct defect_list *list)
408 {
409 struct defect_entry def;
410 int index;
411
412
413 /*
414 * Calculate the fields for the defect struct.
415 */
416 def.cyl = bn2c(blkno);
417 def.head = bn2h(blkno);
418 def.sect = bn2s(blkno);
419 /*
420 * Initialize the unknown fields.
421 */
422 def.bfi = def.nbits = UNKNOWN;
423 /*
424 * Calculate the index into the list that the defect belongs at.
425 */
426 index = sort_defect(&def, list);
427 /*
428 * Add the defect to the list.
429 */
430 add_def(&def, list, index);
431 }
432
433 /*
434 * This routine adds the given defect struct to the defect list at
435 * a precalculated index.
436 */
437 void
add_def(struct defect_entry * def,struct defect_list * list,int index)438 add_def(struct defect_entry *def, struct defect_list *list, int index)
439 {
440 int count, i;
441
442 /*
443 * If adding this defect makes the list overflow into another
444 * sector, allocate the necessary space.
445 */
446 count = list->header.count;
447 if (deflist_size(cur_blksz, count + 1) > deflist_size(cur_blksz, count))
448 list->list = (struct defect_entry *)rezalloc((void *)list->list,
449 deflist_size(cur_blksz, count + 1) * cur_blksz);
450 /*
451 * Slip all the defects after this one down one slot in the list.
452 */
453 for (i = count; i > index; i--)
454 *(list->list + i) = *(list->list + i - 1);
455 /*
456 * Fill in the created hole with this defect.
457 */
458 *(list->list + i) = *def;
459 /*
460 * Increment the count and calculate a new checksum.
461 */
462 list->header.count++;
463 (void) checkdefsum(list, CK_MAKESUM);
464 }
465
466 /*
467 * This routine sets the given defect list back to null.
468 */
469 void
kill_deflist(struct defect_list * list)470 kill_deflist(struct defect_list *list)
471 {
472
473 /*
474 * If it's already null, we're done.
475 */
476 if (list->list == NULL)
477 return;
478 /*
479 * Free the malloc'd space it's using.
480 */
481 destroy_data((char *)list->list);
482 /*
483 * Mark it as null, and clear any flags.
484 */
485 list->list = NULL;
486 list->flags = 0;
487 }
488
489 /*
490 * This routine returns the defect list size
491 * according to the sector size.
492 */
493 int
deflist_size(int secsz,int sz)494 deflist_size(int secsz, int sz)
495 {
496 int rval;
497
498 if (secsz == 0) {
499 secsz = SECSIZE;
500 }
501
502 rval = sz ? ((sz * sizeof (struct defect_entry) +
503 secsz - 1) / secsz) : 1;
504
505 return (rval);
506 }
507