/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* NAME: raid_resync.c
* DESCRIPTION: RAID driver source file containing routines related to resync
* operation.
* ROUTINES PROVIDED FOR EXTERNAL USE:
* resync_request() - get resync lock if available
* release_resync_request() - relinquish resync lock
* erred_check_line() - provide write instruction for erred column
* init_pw_area() - initialize pre-write area
* copy_pw_area() - copy pre-write area from one device to another
*/
#include <sys/sysmacros.h>
extern kmem_cache_t *raid_child_cache;
extern kmem_cache_t *raid_parent_cache;
extern md_resync_t md_cpr_resync;
/*
* NAMES: xor
* DESCRIPTION: Xor two chunks of data together. The data referenced by
* addr1 and addr2 are xor'd together for size and written into
* addr1.
* PARAMETERS: caddr_t addr1 - address of first chunk of data and destination
* caddr_t addr2 - address of second chunk of data
* u_int size - number to xor
*/
static void
{
while (size--) {
}
}
/*
* NAME: release_resync_request
*
* DESCRIPTION: Release resync active flag and reset unit values accordingly.
*
* PARAMETERS: minor_t mnum - minor number identity of metadevice
*
* LOCKS: Expects Unit Writer Lock to be held across call.
*/
void
)
{
un->un_resync_line_index = 0;
}
/*
* NAME: resync_request
*
* DESCRIPTION: Request resync. If resync is available (no current active
* resync), mark unit as resync active and initialize.
*
* PARAMETERS: minor_t mnum - minor number identity of metadevice
* int column_index - index of column to resync
* int copysize - copysize of ioctl request
* md_error_t *ep - error output parameter
*
* RETURN: 0 if resync is available, 1 otherwise.
*
* LOCKS: Expects Unit Writer Lock to be held across call.
*
* NOTE: Sets un_resync_copysize to the input value in copysize, the
* existing value from an incomplete previous resync with an
* input value in copysize, or the lesser of the unit segment
* size or maxio.
*/
/* ARGSUSED */
int
int column_index,
)
{
/* if resync or grow not already active, set resync active for unit */
if (mde)
return (1);
}
(RCS_ERRED | RCS_LAST_ERRED))
else
un->un_resync_line_index = 0;
return (0);
}
/*
* Name: alloc_bufs
*
* DESCRIPTION: Initialize resync_comp buffers.
*
* PARAMETERS: size_t bsize - size of buffer
* buf_t *read_buf1 - first read buf
* buf_t *read_buf2 - second read buf
* buf_t *write_buf - write buf
*/
static void
{
/* allocate buffers, write uses the read_buf1 buffer */
}
void
{
/* zero buf */
/* set b_back and b_forw to point back to buf */
/* set flags size */
/* setup semaphores */
}
void
{
}
void
{
}
/*
* NAME: free_bufs
*
* DESCRIPTION: Free up buffers.
*
* PARAMETERS: size_t bsize - size of buffer
* buf_t *read_buf1 - first read buf
* buf_t *read_buf2 - second read buf
* buf_t *write_buf - write buf
*/
static void
{
}
/*
* NAME: init_pw_area
*
* DESCRIPTION: Initialize pre-write area to all zeros.
*
* PARAMETERS: minor_t mnum - minor number identity of metadevice
* md_dev64_t dev_to_write - index of column to resync
* int column_index - index of column to resync
*
* RETURN: 1 if write error on resync device, otherwise 0
*
* LOCKS: Expects Unit Reader Lock to be held across call.
*/
int
)
{
int error = 0;
int i;
/* magic field is 0 for 4.0 compatability */
0, 0, 0,
0, col, 0);
/* write buf */
error = 1;
break;
}
} /* for */
destroy_buf(&buf);
return (error);
}
/*
* NAME: raid_open_alt
*
* DESCRIPTION: opens the alt device used during resync.
*
* PARAMETERS: un
*
* RETURN: 0 - successfull
* 1 - failed
*
* LOCKS: requires unit writer lock
*/
static int
{
/* correct locks */
/* not already writing to */
/* not already open */
/*
* Open by device id. We use orig_key since alt_dev
* has been set by the caller to be the same as orig_dev.
*/
}
/* failed open */
return (1);
} else {
/* open suceeded */
return (0);
}
} else
/* no alt device to open */
return (1);
}
/*
* NAME: raid_close_alt
*
* DESCRIPTION: closes the alt device used during resync.
*
* PARAMETERS: un - raid unit structure
* indes - raid column
*
* RETURN: none
*
* LOCKS: requires unit writer lock
*/
static void
{
}
static diskaddr_t
{
return (line + line_count);
}
/* states returned by raid_resync_line */
#define RAID_RESYNC_OKAY 0
int
int *single_read,
int *err_col,
{
int resync;
int quit = 0;
int i;
/* find first column to read, skip resync column */
while (leftinseg) {
/* truncate last chunk to end if needed */
else
/*
* One of two scenarios:
* 1) resync device with hotspare ok. This implies that
* we are copying from a good hotspare to a new good original
* device. In this case readb1 is used as the buf for
* the read from the hotspare device.
* 2) For all other cases, including when in case 1) and an
* error is detected on the (formerly good) hotspare device,
* readb1 is used for the initial read. readb2 is used for
* all other reads. Each readb2 buffer is xor'd into the
* readb1 buffer.
*
* In both cases, writeb is used for the write, using readb1's
* buffer.
*
* For case 2, we could alternatively perform the read for all
* devices concurrently to improve performance. However,
* this could diminish performance for concurrent reads and
* writes if low on memory.
*/
/* read first buffer */
/* switch to read from good columns if single_read */
if (*single_read) {
return (RAID_RESYNC_RDERROR);
/*
* at this point just start rebuilding the
* data and go on since the other column
* are ok.
*/
*single_read = 0;
}
}
/* if reading from all non-resync columns */
if (!*single_read) {
/* for each column, read line and xor into write buf */
for (i = 0; i < un->un_totalcolumncnt; i++) {
return (RAID_RESYNC_RDERROR);
/* skip column getting resync'ed */
if (i == resync) {
continue;
}
NULL);
*err_col = i;
}
if (quit)
return (quit);
/* xor readb2 data into readb1 */
} /* for */
}
/* set write block number and perform the write */
if (*single_read == 0) {
}
return (RAID_RESYNC_WRERROR);
}
} /* while */
return (RAID_RESYNC_OKAY);
}
/*
* NAME: resync_comp
*
* DESCRIPTION: Resync the component. Iterate through the raid unit a line at
* a time, read from the good device(s) and write the resync
* device.
*
* PARAMETERS: minor_t mnum - minor number identity of metadevice
* md_raidcs_t *cs - child save struct
*
* RETURN: 0 - successfull
* 1 - failed
* -1 - aborted
*
* LOCKS: Expects Unit Reader Lock to be held across call. Acquires and
* releases Line Reader Lock for per-line I/O.
*/
static void
)
{
int resync;
int i;
int single_read = 0;
int err;
int err_cnt;
int last_err;
/*
* hs_state is the state of the hotspare on the column being resynced
* dev_state is the state of the resync target
*/
if (line_count == 0) { /* handle the case of segsize > maxio */
line_count = 1;
} else
/*
* if the column is not in resync then just bail out.
*/
return;
}
/* identify device to write and its start block */
NULL, 0));
return;
}
single_read = 0;
} else {
single_read = 1;
}
} else {
single_read = 0;
}
/* initialize pre-write area */
}
goto resync_comp_error;
}
/* commit the record */
/* resync each line of the unit */
/*
* Update address range in child struct and lock the line.
*
* The reader version of the line lock is used since only
* resync will use data beyond un_resync_line_index on the
* resync device.
*/
(void) md_unit_readerlock(ui);
/*
* if the column failed to resync then stop writing directly
* to the column.
*/
if (err)
un->un_resync_line_index = 0;
if (err)
break;
break;
}
} /* for */
(void) md_unit_writerlock(ui);
recids[0] = 0;
recids[1] = 0;
switch (err) {
/*
* successful resync
*/
case RAID_RESYNC_OKAY:
/* initialize pre-write area */
/*
* replacing a hot spare
* release the hot spare, which will close the hotspare
* and mark it closed.
*/
/*
* make the resync target the main device and
* mark open
*/
/* alt becomes the device so don't close it */
}
break;
case RAID_RESYNC_WRERROR:
/*
* this is the case where the resync target is
* bad but there is a good hotspare. In this
* case keep the hotspare, and go back to okay.
*/
NULL, 0));
break;
}
}
else
NULL, 0));
break;
case RAID_RESYNC_STATE:
/*
* this is the case where the resync target is
* bad but there is a good hotspare. In this
* case keep the hotspare, and go back to okay.
*/
break;
}
}
break;
case RAID_RESYNC_RDERROR:
}
break;
default:
ASSERT(0);
}
}
/*
* an io operation may have gotten an error and placed a
* column in erred state. This will abort the resync, which
* will end up in last erred. This is ugly so go through
* the columns and do cleanup
*/
err_cnt = 0;
last_err = 0;
for (i = 0; i < un->un_totalcolumncnt; i++) {
continue;
if (i == resync) {
err_cnt++;
} else if (err == RAID_RESYNC_OKAY) {
err_cnt++;
} else {
last_err++;
}
}
else if (last_err == 0) {
} else if (last_err > 0) {
}
un->un_resync_copysize = 0;
/* release unit writer lock and acquire unit reader lock */
(void) md_unit_readerlock(ui);
if (err == RAID_RESYNC_OKAY) {
} else {
RCS_LAST_ERRED) > 1) {
} else {
}
}
}
/*
* NAME: resync_unit
*
* DESCRIPTION: Start of RAID resync thread. Perform up front allocations,
* initializations and consistency checking, then call
* resync_comp to resync the component.
*
* PARAMETERS: minor_t mnum - minor number identity of metadevice
*
* LOCKS: Acquires and releases Unit Reader Lock to maintain unit
* existence during resync.
* Acquires and releases the resync count lock for cpr.
*/
static void
)
{
int resync;
/*
* Increment the raid resync count for cpr
*/
/*
* Allocate parent and child memory pool structures. These are
* only needed to lock raid lines, so only the minimal
* required fields for this purpose are initialized.
*
* Do not use the reserve pool for resync.
*/
/* close raid unit */
/* poke hot spare daemon */
(void) raid_hotspares();
/*
* Decrement the raid resync count for cpr
*/
thread_exit();
}
/*
* NAME: raid_resync_unit
*
* DESCRIPTION: RAID metadevice specific resync routine.
* Open the unit and start resync_unit as a separate thread.
*
* PARAMETERS: minor_t mnum - minor number identity of metadevice
* md_error_t *ep - output error parameter
*
* RETURN: On error return 1 or set ep to nonzero, otherwise return 0.
*
* LOCKS: Acquires and releases Unit Writer Lock.
*/
int
)
{
/* Don't start a resync if the device is not available */
}
(void) md_unit_writerlock(ui);
}
/* start resync_unit thread */
return (0);
}