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 Software.Distribution@CS.CMU.EDU
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 * HISTORY
28 * $Log: rz_disk_bbr.c,v $
29 * Revision 2.11 93/05/10 21:22:38 rvb
30 * Removed depends on DEV_BSIZE.
31 * [93/05/06 10:09:46 af]
32 *
33 * Revision 2.10 92/08/03 17:53:51 jfriedl
34 * removed silly prototypes
35 * [92/08/02 jfriedl]
36 *
37 * Revision 2.9 92/05/22 15:51:13 jfriedl
38 * Blooper, unterminated comment took away some (working, I swear)
39 * code. Found by Jeff Friedl.
40 * [92/05/17 af]
41 *
42 * Revision 2.8 92/05/21 17:23:40 jfriedl
43 * Cleanup to quiet gcc warnings.
44 * [92/05/18 jfriedl]
45 *
46 * Revision 2.7 92/02/23 22:44:25 elf
47 * Changed the interface of a number of functions not to
48 * require the scsi_softc pointer any longer. It was
49 * mostly unused, now it can be found via tgt->masterno.
50 * [92/02/22 19:30:35 af]
51 *
52 * Revision 2.6 91/08/24 12:27:58 af
53 * Fixed includes.
54 * [91/08/02 03:45:46 af]
55 *
56 * Revision 2.5 91/07/09 23:22:33 danner
57 * Upgraded to new label technology.
58 * [91/07/09 11:16:12 danner]
59 *
60 * Revision 2.4 91/06/19 11:57:06 rvb
61 * File moved here from mips/PMAX since it is now "MI" code, also
62 * used by Vax3100 and soon -- the omron luna88k.
63 * [91/06/04 rvb]
64 *
65 * Revision 2.3 91/05/14 17:26:42 mrt
66 * Correcting copyright
67 *
68 * Revision 2.2 91/05/13 06:04:29 af
69 * Created.
70 * [91/04/30 af]
71 *
72 */
73 /*
74 * File: rz_disk_bbr.c
75 * Author: Alessandro Forin, Carnegie Mellon University
76 * Date: 4/91
77 *
78 * Top layer of the SCSI driver: interface with the MI.
79 * This file contains bad-block management functions
80 * (retry, replace) for disk-like devices.
81 */
82
83 #include <mach/std_types.h>
84 #include <scsi/compat_30.h>
85
86 #include <scsi/scsi.h>
87 #include <scsi/scsi_defs.h>
88 #include <scsi/rz.h>
89
90
91
92 int scsi_bbr_retries = 10;
93
94 #define BBR_ACTION_COMPLETE 1
95 #define BBR_ACTION_RETRY_READ 2
96 #define BBR_ACTION_REASSIGN 3
97 #define BBR_ACTION_COPY 4
98 #define BBR_ACTION_VERIFY 5
99
100 static void make_msf(); /* forward */
101
102 /*
103 * Bad block replacement routine, invoked on
104 * unrecovereable disk read/write errors.
105 */
106 boolean_t
107 scdisk_bad_block_repl(tgt, blockno)
108 target_info_t *tgt;
109 unsigned int blockno;
110 {
111 register io_req_t ior = tgt->ior;
112
113 if (scsi_no_automatic_bbr || (ior->io_op & IO_INTERNAL))
114 return FALSE;
115
116 /* signal we took over */
117 tgt->flags |= TGT_BBR_ACTIVE;
118
119 printf("%s", "Attempting bad block replacement..");
120
121 tgt->dev_info.disk.b.badblockno = blockno;
122 tgt->dev_info.disk.b.retry_count = 0;
123
124 tgt->dev_info.disk.b.save_rec = ior->io_recnum;
125 tgt->dev_info.disk.b.save_addr = ior->io_data;
126 tgt->dev_info.disk.b.save_count = ior->io_count;
127 tgt->dev_info.disk.b.save_resid = ior->io_residual;
128
129 /*
130 * On a write all we need is to rewire the offending block.
131 * Note that the sense data identified precisely which 512 sector
132 * is bad. At the end we'll retry the entire write, so if there
133 * is more than one bad sector involved they will be handled one
134 * at a time.
135 */
136 if ((ior->io_op & IO_READ) == 0) {
137 char msf[sizeof(int)];
138 ior->io_temporary = BBR_ACTION_COMPLETE;
139 printf("%s", "just reassign..");
140 make_msf(msf,blockno);
141 scsi_reassign_blocks( tgt, msf, 1, ior);
142 } else
143 /*
144 * This is more complicated. We asked for N bytes, and somewhere
145 * in there there is a chunk of bad data. First off, we should retry
146 * at least a couple of times to retrieve that data [yes the drive
147 * should have done its best already so what]. If that fails we
148 * should recover as much good data as possible (before the bad one).
149 */
150 {
151 ior->io_temporary = BBR_ACTION_RETRY_READ;
152 printf("%s", "retry read..");
153 ior->io_residual = 0;
154 scdisk_start_rw(tgt, ior);
155 }
156
157 return TRUE;
158 }
159
160 static
161 void make_msf(buf,val)
162 unsigned char *buf;
163 unsigned int val;
164 {
165 *buf++ = val >> 24;
166 *buf++ = val >> 16;
167 *buf++ = val >> 8;
168 *buf++ = val >> 0;
169 }
170
171 /*
172 * This effectively replaces the strategy routine during bbr.
173 */
174 void scdisk_bbr_start( tgt, done)
175 target_info_t *tgt;
176 boolean_t done;
177 {
178 register io_req_t ior = tgt->ior;
179 char *msg;
180
181 switch (ior->io_temporary) {
182
183 case BBR_ACTION_COMPLETE:
184
185 /* all done, either way */
186 fin:
187 tgt->flags &= ~TGT_BBR_ACTIVE;
188 ior->io_recnum = tgt->dev_info.disk.b.save_rec;
189 ior->io_data = tgt->dev_info.disk.b.save_addr;
190 ior->io_count = tgt->dev_info.disk.b.save_count;
191 ior->io_residual = tgt->dev_info.disk.b.save_resid;
192
193 if (tgt->done == SCSI_RET_SUCCESS) {
194 /* restart normal life */
195 register unsigned int xferred;
196 if (xferred = ior->io_residual) {
197 ior->io_data -= xferred;
198 ior->io_count += xferred;
199 ior->io_recnum -= xferred / tgt->block_size;
200 ior->io_residual = 0;
201 }
202 /* from the beginning */
203 ior->io_error = 0;
204 msg = "done, restarting.";
205 } else {
206 /* we could not fix it. Tell user and give up */
207 tgt->ior = ior->io_next;
208 iodone(ior);
209 msg = "done, but could not recover.";
210 }
211
212 printf("%s\n", msg);
213 scdisk_start( tgt, FALSE);
214 return;
215
216 case BBR_ACTION_RETRY_READ:
217
218 /* see if retry worked, if not do it again */
219 if (tgt->done == SCSI_RET_SUCCESS) {
220 char msf[sizeof(int)];
221
222 /* whew, retry worked. Now rewire that bad block
223 * and don't forget to copy the good data over */
224
225 tgt->dev_info.disk.b.retry_count = 0;
226 printf("%s", "ok now, reassign..");
227 ior->io_temporary = BBR_ACTION_COPY;
228 make_msf(msf, tgt->dev_info.disk.b.badblockno);
229 scsi_reassign_blocks( tgt, msf, 1, ior);
230 return;
231 }
232 if (tgt->dev_info.disk.b.retry_count++ < scsi_bbr_retries) {
233 scdisk_start_rw( tgt, ior);
234 return;
235 }
236 /* retrying was hopeless. Leave the bad block there for maintainance */
237 /* because we do not know what to write on it */
238 printf("%s%d%s", "failed after ", scsi_bbr_retries, " retries..");
239 goto fin;
240
241
242 case BBR_ACTION_COPY:
243
244 /* retrying succeded and we rewired the bad block. */
245 if (tgt->done == SCSI_RET_SUCCESS) {
246 unsigned int tmp;
247
248 printf("%s", "ok, rewrite..");
249
250 /* writeback only the bad sector */
251
252 /* map blockno back to partition offset */
253 tmp = rzpartition(ior->io_unit);
254 tmp = tgt->dev_info.disk.b.badblockno -
255 tgt->dev_info.disk.l.d_partitions[tmp].p_offset;
256 ior->io_data += (tmp - ior->io_recnum) * tgt->block_size;
257 ior->io_recnum = tmp;
258 ior->io_count = tgt->block_size;
259 ior->io_op &= ~IO_READ;
260
261 ior->io_temporary = BBR_ACTION_VERIFY;
262 scdisk_start_rw( tgt, ior);
263 } else {
264
265 /* either unsupported command, or repl table full */
266 printf("%s", "reassign failed (really needs reformatting), ");
267 ior->io_error = 0;
268 goto fin;
269 }
270 break;
271
272 case BBR_ACTION_VERIFY:
273
274 if (tgt->done == SCSI_RET_SUCCESS) {
275 ior->io_op |= IO_READ;
276 goto fin;
277 }
278
279 if (tgt->dev_info.disk.b.retry_count++ > scsi_bbr_retries) {
280 printf("%s%d%s", "failed after ",
281 scsi_bbr_retries, " retries..");
282 ior->io_op |= IO_READ;
283 goto fin;
284 }
285
286 /* retry, we are *this* close to success.. */
287 scdisk_start_rw( tgt, ior);
288
289 break;
290
291 case BBR_ACTION_REASSIGN:
292
293 /* if we wanted to issue the reassign multiple times */
294 /* XXX unimplemented XXX */
295
296 default: /* snafu */
297 panic("scdisk_bbr_start");
298 }
299 }
Cache object: ad994858165055c9e015d766d25146c3
|