OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [ftape/] [lowlevel/] [ftape-write.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Copyright (C) 1993-1995 Bas Laarhoven,
3
 *                (C) 1996-1997 Claus-Justus Heine.
4
 
5
 This program is free software; you can redistribute it and/or modify
6
 it under the terms of the GNU General Public License as published by
7
 the Free Software Foundation; either version 2, or (at your option)
8
 any later version.
9
 
10
 This program is distributed in the hope that it will be useful,
11
 but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 GNU General Public License for more details.
14
 
15
 You should have received a copy of the GNU General Public License
16
 along with this program; see the file COPYING.  If not, write to
17
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
 
19
 *
20
 * $Source: /home/marcus/revision_ctrl_test/oc_cvs/cvs/or1k/linux/linux-2.4/drivers/char/ftape/lowlevel/ftape-write.c,v $
21
 * $Revision: 1.1.1.1 $
22
 * $Date: 2004-04-15 02:02:33 $
23
 *
24
 *      This file contains the writing code
25
 *      for the QIC-117 floppy-tape driver for Linux.
26
 */
27
 
28
#include <linux/string.h>
29
#include <linux/errno.h>
30
#include <linux/mm.h>
31
#include <asm/segment.h>
32
 
33
#include <linux/ftape.h>
34
#include <linux/qic117.h>
35
#include "../lowlevel/ftape-tracing.h"
36
#include "../lowlevel/ftape-write.h"
37
#include "../lowlevel/ftape-read.h"
38
#include "../lowlevel/ftape-io.h"
39
#include "../lowlevel/ftape-ctl.h"
40
#include "../lowlevel/ftape-rw.h"
41
#include "../lowlevel/ftape-ecc.h"
42
#include "../lowlevel/ftape-bsm.h"
43
#include "../lowlevel/fdc-isr.h"
44
 
45
/*      Global vars.
46
 */
47
 
48
/*      Local vars.
49
 */
50
static int last_write_failed;
51
 
52
void ftape_zap_write_buffers(void)
53
{
54
        int i;
55
 
56
        for (i = 0; i < ft_nr_buffers; ++i) {
57
                ft_buffer[i]->status = done;
58
        }
59
        ftape_reset_buffer();
60
}
61
 
62
static int copy_and_gen_ecc(void *destination,
63
                            const void *source,
64
                            const SectorMap bad_sector_map)
65
{
66
        int result;
67
        struct memory_segment mseg;
68
        int bads = count_ones(bad_sector_map);
69
        TRACE_FUN(ft_t_any);
70
 
71
        if (bads > 0) {
72
                TRACE(ft_t_noise, "bad sectors in map: %d", bads);
73
        }
74
        if (bads + 3 >= FT_SECTORS_PER_SEGMENT) {
75
                TRACE(ft_t_noise, "empty segment");
76
                mseg.blocks = 0; /* skip entire segment */
77
                result = 0;      /* nothing written */
78
        } else {
79
                mseg.blocks = FT_SECTORS_PER_SEGMENT - bads;
80
                mseg.data = destination;
81
                memcpy(mseg.data, source, (mseg.blocks - 3) * FT_SECTOR_SIZE);
82
                result = ftape_ecc_set_segment_parity(&mseg);
83
                if (result < 0) {
84
                        TRACE(ft_t_err, "ecc_set_segment_parity failed");
85
                } else {
86
                        result = (mseg.blocks - 3) * FT_SECTOR_SIZE;
87
                }
88
        }
89
        TRACE_EXIT result;
90
}
91
 
92
 
93
int ftape_start_writing(const ft_write_mode_t mode)
94
{
95
        buffer_struct *head = ftape_get_buffer(ft_queue_head);
96
        int segment_id = head->segment_id;
97
        int result;
98
        buffer_state_enum wanted_state = (mode == FT_WR_DELETE
99
                                          ? deleting
100
                                          : writing);
101
        TRACE_FUN(ft_t_flow);
102
 
103
        if ((ft_driver_state != wanted_state) || head->status != waiting) {
104
                TRACE_EXIT 0;
105
        }
106
        ftape_setup_new_segment(head, segment_id, 1);
107
        if (mode == FT_WR_SINGLE) {
108
                /* stop tape instead of pause */
109
                head->next_segment = 0;
110
        }
111
        ftape_calc_next_cluster(head); /* prepare */
112
        head->status = ft_driver_state; /* either writing or deleting */
113
        if (ft_runner_status == idle) {
114
                TRACE(ft_t_noise,
115
                      "starting runner for segment %d", segment_id);
116
                TRACE_CATCH(ftape_start_tape(segment_id,head->sector_offset),);
117
        } else {
118
                TRACE(ft_t_noise, "runner not idle, not starting tape");
119
        }
120
        /* go */
121
        result = fdc_setup_read_write(head, (mode == FT_WR_DELETE
122
                                             ? FDC_WRITE_DELETED : FDC_WRITE));
123
        ftape_set_state(wanted_state); /* should not be necessary */
124
        TRACE_EXIT result;
125
}
126
 
127
/*  Wait until all data is actually written to tape.
128
 *
129
 *  There is a problem: when the tape runs into logical EOT, then this
130
 *  failes. We need to restart the runner in this case.
131
 */
132
int ftape_loop_until_writes_done(void)
133
{
134
        buffer_struct *head;
135
        TRACE_FUN(ft_t_flow);
136
 
137
        while ((ft_driver_state == writing || ft_driver_state == deleting) &&
138
               ftape_get_buffer(ft_queue_head)->status != done) {
139
                /* set the runner status to idle if at lEOT */
140
                TRACE_CATCH(ftape_handle_logical_eot(), last_write_failed = 1);
141
                /* restart the tape if necessary */
142
                if (ft_runner_status == idle) {
143
                        TRACE(ft_t_noise, "runner is idle, restarting");
144
                        if (ft_driver_state == deleting) {
145
                                TRACE_CATCH(ftape_start_writing(FT_WR_DELETE),
146
                                            last_write_failed = 1);
147
                        } else {
148
                                TRACE_CATCH(ftape_start_writing(FT_WR_MULTI),
149
                                            last_write_failed = 1);
150
                        }
151
                }
152
                TRACE(ft_t_noise, "tail: %d, head: %d",
153
                      ftape_buffer_id(ft_queue_tail),
154
                      ftape_buffer_id(ft_queue_head));
155
                TRACE_CATCH(fdc_interrupt_wait(5 * FT_SECOND),
156
                            last_write_failed = 1);
157
                head = ftape_get_buffer(ft_queue_head);
158
                if (head->status == error) {
159
                        /* Allow escape from loop when signaled !
160
                         */
161
                        FT_SIGNAL_EXIT(_DONT_BLOCK);
162
                        if (head->hard_error_map != 0) {
163
                                /*  Implement hard write error recovery here
164
                                 */
165
                        }
166
                        /* retry this one */
167
                        head->status = waiting;
168
                        if (ft_runner_status == aborting) {
169
                                ftape_dumb_stop();
170
                        }
171
                        if (ft_runner_status != idle) {
172
                                TRACE_ABORT(-EIO, ft_t_err,
173
                                            "unexpected state: "
174
                                            "ft_runner_status != idle");
175
                        }
176
                        ftape_start_writing(ft_driver_state == deleting
177
                                            ? FT_WR_MULTI : FT_WR_DELETE);
178
                }
179
                TRACE(ft_t_noise, "looping until writes done");
180
        }
181
        ftape_set_state(idle);
182
        TRACE_EXIT 0;
183
}
184
 
185
/*      Write given segment from buffer at address to tape.
186
 */
187
static int write_segment(const int segment_id,
188
                         const void *address,
189
                         const ft_write_mode_t write_mode)
190
{
191
        int bytes_written = 0;
192
        buffer_struct *tail;
193
        buffer_state_enum wanted_state = (write_mode == FT_WR_DELETE
194
                                          ? deleting : writing);
195
        TRACE_FUN(ft_t_flow);
196
 
197
        TRACE(ft_t_noise, "segment_id = %d", segment_id);
198
        if (ft_driver_state != wanted_state) {
199
                if (ft_driver_state == deleting ||
200
                    wanted_state == deleting) {
201
                        TRACE_CATCH(ftape_loop_until_writes_done(),);
202
                }
203
                TRACE(ft_t_noise, "calling ftape_abort_operation");
204
                TRACE_CATCH(ftape_abort_operation(),);
205
                ftape_zap_write_buffers();
206
                ftape_set_state(wanted_state);
207
        }
208
        /*    if all buffers full we'll have to wait...
209
         */
210
        ftape_wait_segment(wanted_state);
211
        tail = ftape_get_buffer(ft_queue_tail);
212
        switch(tail->status) {
213
        case done:
214
                ft_history.defects += count_ones(tail->hard_error_map);
215
                break;
216
        case waiting:
217
                /* this could happen with multiple EMPTY_SEGMENTs, but
218
                 * shouldn't happen any more as we re-start the runner even
219
                 * with an empty segment.
220
                 */
221
                bytes_written = -EAGAIN;
222
                break;
223
        case error:
224
                /*  setup for a retry
225
                 */
226
                tail->status = waiting;
227
                bytes_written = -EAGAIN; /* force retry */
228
                if (tail->hard_error_map != 0) {
229
                        TRACE(ft_t_warn,
230
                              "warning: %d hard error(s) in written segment",
231
                              count_ones(tail->hard_error_map));
232
                        TRACE(ft_t_noise, "hard_error_map = 0x%08lx",
233
                              (long)tail->hard_error_map);
234
                        /*  Implement hard write error recovery here
235
                         */
236
                }
237
                break;
238
        default:
239
                TRACE_ABORT(-EIO, ft_t_err,
240
                            "wait for empty segment failed, tail status: %d",
241
                            tail->status);
242
        }
243
        /*    should runner stop ?
244
         */
245
        if (ft_runner_status == aborting) {
246
                buffer_struct *head = ftape_get_buffer(ft_queue_head);
247
                if (head->status == wanted_state) {
248
                        head->status = done; /* ???? */
249
                }
250
                /*  don't call abort_operation(), we don't want to zap
251
                 *  the dma buffers
252
                 */
253
                TRACE_CATCH(ftape_dumb_stop(),);
254
        } else {
255
                /*  If just passed last segment on tape: wait for BOT
256
                 *  or EOT mark. Sets ft_runner_status to idle if at lEOT
257
                 *  and successful
258
                 */
259
                TRACE_CATCH(ftape_handle_logical_eot(),);
260
        }
261
        if (tail->status == done) {
262
                /* now at least one buffer is empty, fill it with our
263
                 * data.  skip bad sectors and generate ecc.
264
                 * copy_and_gen_ecc return nr of bytes written, range
265
                 * 0..29 Kb inclusive!
266
                 *
267
                 * Empty segments are handled inside coyp_and_gen_ecc()
268
                 */
269
                if (write_mode != FT_WR_DELETE) {
270
                        TRACE_CATCH(bytes_written = copy_and_gen_ecc(
271
                                tail->address, address,
272
                                ftape_get_bad_sector_entry(segment_id)),);
273
                }
274
                tail->segment_id = segment_id;
275
                tail->status = waiting;
276
                tail = ftape_next_buffer(ft_queue_tail);
277
        }
278
        /*  Start tape only if all buffers full or flush mode.
279
         *  This will give higher probability of streaming.
280
         */
281
        if (ft_runner_status != running &&
282
            ((tail->status == waiting &&
283
              ftape_get_buffer(ft_queue_head) == tail) ||
284
             write_mode != FT_WR_ASYNC)) {
285
                TRACE_CATCH(ftape_start_writing(write_mode),);
286
        }
287
        TRACE_EXIT bytes_written;
288
}
289
 
290
/*  Write as much as fits from buffer to the given segment on tape
291
 *  and handle retries.
292
 *  Return the number of bytes written (>= 0), or:
293
 *      -EIO          write failed
294
 *      -EINTR        interrupted by signal
295
 *      -ENOSPC       device full
296
 */
297
int ftape_write_segment(const int segment_id,
298
                        const void *buffer,
299
                        const ft_write_mode_t flush)
300
{
301
        int retry = 0;
302
        int result;
303
        TRACE_FUN(ft_t_flow);
304
 
305
        ft_history.used |= 2;
306
        if (segment_id >= ft_tracks_per_tape*ft_segments_per_track) {
307
                /* tape full */
308
                TRACE_ABORT(-ENOSPC, ft_t_err,
309
                            "invalid segment id: %d (max %d)",
310
                            segment_id,
311
                            ft_tracks_per_tape * ft_segments_per_track -1);
312
        }
313
        for (;;) {
314
                if ((result = write_segment(segment_id, buffer, flush)) >= 0) {
315
                        if (result == 0) { /* empty segment */
316
                                TRACE(ft_t_noise,
317
                                      "empty segment, nothing written");
318
                        }
319
                        TRACE_EXIT result;
320
                }
321
                if (result == -EAGAIN) {
322
                        if (++retry > 100) { /* give up */
323
                                TRACE_ABORT(-EIO, ft_t_err,
324
                                      "write failed, >100 retries in segment");
325
                        }
326
                        TRACE(ft_t_warn, "write error, retry %d (%d)",
327
                              retry,
328
                              ftape_get_buffer(ft_queue_tail)->segment_id);
329
                } else {
330
                        TRACE_ABORT(result, ft_t_err,
331
                                    "write_segment failed, error: %d", result);
332
                }
333
                /* Allow escape from loop when signaled !
334
                 */
335
                FT_SIGNAL_EXIT(_DONT_BLOCK);
336
        }
337
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.