|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: rz_disk_bbr.c
28: * Author: Alessandro Forin, Carnegie Mellon University
29: * Date: 4/91
30: *
31: * Top layer of the SCSI driver: interface with the MI.
32: * This file contains bad-block management functions
33: * (retry, replace) for disk-like devices.
34: */
35:
36: #include <mach/std_types.h>
37: #include <scsi/compat_30.h>
38:
39: #include <scsi/scsi.h>
40: #include <scsi/scsi_defs.h>
41: #include <scsi/rz.h>
42:
43: #if (NSCSI > 0)
44:
45: int scsi_bbr_retries = 10;
46:
47: #define BBR_ACTION_COMPLETE 1
48: #define BBR_ACTION_RETRY_READ 2
49: #define BBR_ACTION_REASSIGN 3
50: #define BBR_ACTION_COPY 4
51: #define BBR_ACTION_VERIFY 5
52:
53: static void make_msf(); /* forward */
54:
55: /*
56: * Bad block replacement routine, invoked on
57: * unrecovereable disk read/write errors.
58: */
59: boolean_t
60: scdisk_bad_block_repl(tgt, blockno)
61: target_info_t *tgt;
62: unsigned int blockno;
63: {
64: register io_req_t ior = tgt->ior;
65:
66: if (scsi_no_automatic_bbr || (ior->io_op & IO_INTERNAL))
67: return FALSE;
68:
69: /* signal we took over */
70: tgt->flags |= TGT_BBR_ACTIVE;
71:
72: printf("%s", "Attempting bad block replacement..");
73:
74: tgt->dev_info.disk.b.badblockno = blockno;
75: tgt->dev_info.disk.b.retry_count = 0;
76:
77: tgt->dev_info.disk.b.save_rec = ior->io_recnum;
78: tgt->dev_info.disk.b.save_addr = ior->io_data;
79: tgt->dev_info.disk.b.save_count = ior->io_count;
80: tgt->dev_info.disk.b.save_resid = ior->io_residual;
81:
82: /*
83: * On a write all we need is to rewire the offending block.
84: * Note that the sense data identified precisely which 512 sector
85: * is bad. At the end we'll retry the entire write, so if there
86: * is more than one bad sector involved they will be handled one
87: * at a time.
88: */
89: if ((ior->io_op & IO_READ) == 0) {
90: char msf[sizeof(int)];
91: ior->io_temporary = BBR_ACTION_COMPLETE;
92: printf("%s", "just reassign..");
93: make_msf(msf,blockno);
94: scsi_reassign_blocks( tgt, msf, 1, ior);
95: } else
96: /*
97: * This is more complicated. We asked for N bytes, and somewhere
98: * in there there is a chunk of bad data. First off, we should retry
99: * at least a couple of times to retrieve that data [yes the drive
100: * should have done its best already so what]. If that fails we
101: * should recover as much good data as possible (before the bad one).
102: */
103: {
104: ior->io_temporary = BBR_ACTION_RETRY_READ;
105: printf("%s", "retry read..");
106: ior->io_residual = 0;
107: scdisk_start_rw(tgt, ior);
108: }
109:
110: return TRUE;
111: }
112:
113: static
114: void make_msf(buf,val)
115: unsigned char *buf;
116: unsigned int val;
117: {
118: *buf++ = val >> 24;
119: *buf++ = val >> 16;
120: *buf++ = val >> 8;
121: *buf++ = val >> 0;
122: }
123:
124: /*
125: * This effectively replaces the strategy routine during bbr.
126: */
127: void scdisk_bbr_start( tgt, done)
128: target_info_t *tgt;
129: boolean_t done;
130: {
131: register io_req_t ior = tgt->ior;
132: char *msg;
133:
134: switch (ior->io_temporary) {
135:
136: case BBR_ACTION_COMPLETE:
137:
138: /* all done, either way */
139: fin:
140: tgt->flags &= ~TGT_BBR_ACTIVE;
141: ior->io_recnum = tgt->dev_info.disk.b.save_rec;
142: ior->io_data = tgt->dev_info.disk.b.save_addr;
143: ior->io_count = tgt->dev_info.disk.b.save_count;
144: ior->io_residual = tgt->dev_info.disk.b.save_resid;
145:
146: if (tgt->done == SCSI_RET_SUCCESS) {
147: /* restart normal life */
148: register unsigned int xferred;
149: if (xferred = ior->io_residual) {
150: ior->io_data -= xferred;
151: ior->io_count += xferred;
152: ior->io_recnum -= xferred / tgt->block_size;
153: ior->io_residual = 0;
154: }
155: /* from the beginning */
156: ior->io_error = 0;
157: msg = "done, restarting.";
158: } else {
159: /* we could not fix it. Tell user and give up */
160: tgt->ior = ior->io_next;
161: iodone(ior);
162: msg = "done, but could not recover.";
163: }
164:
165: printf("%s\n", msg);
166: scdisk_start( tgt, FALSE);
167: return;
168:
169: case BBR_ACTION_RETRY_READ:
170:
171: /* see if retry worked, if not do it again */
172: if (tgt->done == SCSI_RET_SUCCESS) {
173: char msf[sizeof(int)];
174:
175: /* whew, retry worked. Now rewire that bad block
176: * and don't forget to copy the good data over */
177:
178: tgt->dev_info.disk.b.retry_count = 0;
179: printf("%s", "ok now, reassign..");
180: ior->io_temporary = BBR_ACTION_COPY;
181: make_msf(msf, tgt->dev_info.disk.b.badblockno);
182: scsi_reassign_blocks( tgt, msf, 1, ior);
183: return;
184: }
185: if (tgt->dev_info.disk.b.retry_count++ < scsi_bbr_retries) {
186: scdisk_start_rw( tgt, ior);
187: return;
188: }
189: /* retrying was hopeless. Leave the bad block there for maintainance */
190: /* because we do not know what to write on it */
191: printf("%s%d%s", "failed after ", scsi_bbr_retries, " retries..");
192: goto fin;
193:
194:
195: case BBR_ACTION_COPY:
196:
197: /* retrying succeded and we rewired the bad block. */
198: if (tgt->done == SCSI_RET_SUCCESS) {
199: unsigned int tmp;
200: struct diskpart *label;
201:
202: printf("%s", "ok, rewrite..");
203:
204: /* writeback only the bad sector */
205:
206: /* map blockno back to partition offset */
207: /* !!! partition code changes: */
208: tmp = rzpartition(ior->io_unit);
209: /* label=lookup_part(array, tmp +1); */
210: tmp = tgt->dev_info.disk.b.badblockno -
211: /* label->start; */
212: /* #if 0 */
213: tgt->dev_info.disk.l.d_partitions[tmp].p_offset;
214: /* #endif 0 */
215: ior->io_data += (tmp - ior->io_recnum) * tgt->block_size;
216: ior->io_recnum = tmp;
217: ior->io_count = tgt->block_size;
218: ior->io_op &= ~IO_READ;
219:
220: ior->io_temporary = BBR_ACTION_VERIFY;
221: scdisk_start_rw( tgt, ior);
222: } else {
223:
224: /* either unsupported command, or repl table full */
225: printf("%s", "reassign failed (really needs reformatting), ");
226: ior->io_error = 0;
227: goto fin;
228: }
229: break;
230:
231: case BBR_ACTION_VERIFY:
232:
233: if (tgt->done == SCSI_RET_SUCCESS) {
234: ior->io_op |= IO_READ;
235: goto fin;
236: }
237:
238: if (tgt->dev_info.disk.b.retry_count++ > scsi_bbr_retries) {
239: printf("%s%d%s", "failed after ",
240: scsi_bbr_retries, " retries..");
241: ior->io_op |= IO_READ;
242: goto fin;
243: }
244:
245: /* retry, we are *this* close to success.. */
246: scdisk_start_rw( tgt, ior);
247:
248: break;
249:
250: case BBR_ACTION_REASSIGN:
251:
252: /* if we wanted to issue the reassign multiple times */
253: /* XXX unimplemented XXX */
254:
255: default: /* snafu */
256: panic("scdisk_bbr_start");
257: }
258: }
259: #endif /* NSCSI > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.