164987Smsmith/*-
273050Smsmith * Copyright (c) 2000, 2001 Michael Smith
364987Smsmith * Copyright (c) 2000 BSDi
464987Smsmith * All rights reserved.
564987Smsmith *
664987Smsmith * Redistribution and use in source and binary forms, with or without
764987Smsmith * modification, are permitted provided that the following conditions
864987Smsmith * are met:
964987Smsmith * 1. Redistributions of source code must retain the above copyright
1064987Smsmith *    notice, this list of conditions and the following disclaimer.
1164987Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1264987Smsmith *    notice, this list of conditions and the following disclaimer in the
1364987Smsmith *    documentation and/or other materials provided with the distribution.
1464987Smsmith *
1564987Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1664987Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1764987Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1864987Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1964987Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2064987Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2164987Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2264987Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2364987Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2464987Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2564987Smsmith * SUCH DAMAGE.
2664987Smsmith *
2764987Smsmith *	$FreeBSD$
2864987Smsmith */
2964987Smsmith
3064987Smsmith/********************************************************************************
3164987Smsmith ********************************************************************************
3264987Smsmith                                                     Driver Parameter Definitions
3364987Smsmith ********************************************************************************
3464987Smsmith ********************************************************************************/
3564987Smsmith
3664987Smsmith/*
3764987Smsmith * The firmware interface allows for a 16-bit command identifier.  A lookup
3864987Smsmith * table this size (256k) would be too expensive, so we cap ourselves at a
3964987Smsmith * reasonable limit.
4064987Smsmith */
4179695Smsmith#define MLY_MAX_COMMANDS	256	/* max commands per controller */
4264987Smsmith
4364987Smsmith/*
4464987Smsmith * The firmware interface allows for a 16-bit s/g list length.  We limit
4564987Smsmith * ourselves to a reasonable maximum and ensure alignment.
4664987Smsmith */
4779695Smsmith#define MLY_MAX_SGENTRIES	64	/* max S/G entries, limit 65535 */
4864987Smsmith
4979695Smsmith/*
5079695Smsmith * The interval at which we poke the controller for status updates (in seconds).
5179695Smsmith */
5279695Smsmith#define MLY_PERIODIC_INTERVAL	1
5379695Smsmith
5464987Smsmith/********************************************************************************
5564987Smsmith ********************************************************************************
5673050Smsmith                                                      Cross-version Compatibility
5764987Smsmith ********************************************************************************
5864987Smsmith ********************************************************************************/
5964987Smsmith
6064987Smsmith# include <sys/taskqueue.h>
6164987Smsmith
6279695Smsmith#ifndef INTR_ENTROPY
6379695Smsmith# define INTR_ENTROPY 0
6479695Smsmith#endif
6579695Smsmith
6673050Smsmith/********************************************************************************
6773050Smsmith ********************************************************************************
6873050Smsmith                                                      Driver Variable Definitions
6973050Smsmith ********************************************************************************
7073050Smsmith ********************************************************************************/
7173050Smsmith
7264987Smsmith/*
7364987Smsmith * Debugging levels:
7464987Smsmith *  0 - quiet, only emit warnings
7564987Smsmith *  1 - noisy, emit major function points and things done
7664987Smsmith *  2 - extremely noisy, emit trace items in loops, etc.
7764987Smsmith */
7864987Smsmith#ifdef MLY_DEBUG
7987599Sobrien# define debug(level, fmt, args...)	do { if (level <= MLY_DEBUG) printf("%s: " fmt "\n", __func__ , ##args); } while(0)
8087599Sobrien# define debug_called(level)		do { if (level <= MLY_DEBUG) printf("%s: called\n", __func__); } while(0)
8164987Smsmith# define debug_struct(s)		printf("  SIZE %s: %d\n", #s, sizeof(struct s))
8264987Smsmith# define debug_union(s)			printf("  SIZE %s: %d\n", #s, sizeof(union s))
8364987Smsmith# define debug_field(s, f)		printf("  OFFSET %s.%s: %d\n", #s, #f, ((int)&(((struct s *)0)->f)))
8464987Smsmithextern void		mly_printstate0(void);
8564987Smsmithextern struct mly_softc	*mly_softc0;
8664987Smsmith#else
8764987Smsmith# define debug(level, fmt, args...)
8864987Smsmith# define debug_called(level)
8964987Smsmith# define debug_struct(s)
9064987Smsmith#endif
9164987Smsmith
9264987Smsmith#define mly_printf(sc, fmt, args...)	device_printf(sc->mly_dev, fmt , ##args)
9364987Smsmith
9464987Smsmith/*
9564987Smsmith * Per-device structure, used to save persistent state on devices.
9664987Smsmith *
9764987Smsmith * Note that this isn't really Bus/Target/Lun since we don't support
9864987Smsmith * lun != 0 at this time.
9964987Smsmith */
10064987Smsmithstruct mly_btl {
10164987Smsmith    int			mb_flags;
10264987Smsmith#define MLY_BTL_PHYSICAL	(1<<0)		/* physical device */
10364987Smsmith#define MLY_BTL_LOGICAL		(1<<1)		/* logical device */
10464987Smsmith#define MLY_BTL_PROTECTED	(1<<2)		/* device is protected - I/O not allowed */
10564987Smsmith#define MLY_BTL_RESCAN		(1<<3)		/* device needs to be rescanned */
10664987Smsmith    char		mb_name[16];		/* peripheral attached to this device */
10764987Smsmith    int			mb_state;		/* see 8.1 */
10864987Smsmith    int			mb_type;		/* see 8.2 */
10973050Smsmith
11073050Smsmith    /* physical devices only */
11173050Smsmith    int			mb_speed;		/* interface transfer rate */
11273050Smsmith    int			mb_width;		/* interface width */
11364987Smsmith};
11464987Smsmith
11564987Smsmith/*
11664987Smsmith * Per-command control structure.
11764987Smsmith */
11864987Smsmithstruct mly_command {
11964987Smsmith    TAILQ_ENTRY(mly_command)	mc_link;	/* list linkage */
12064987Smsmith
12164987Smsmith    struct mly_softc		*mc_sc;		/* controller that owns us */
12264987Smsmith    u_int16_t			mc_slot;	/* command slot we occupy */
12364987Smsmith    int				mc_flags;
12473050Smsmith#define MLY_CMD_BUSY		(1<<0)		/* command is being run, or ready to run, or not completed */
12573050Smsmith#define MLY_CMD_COMPLETE	(1<<1)		/* command has been completed */
12673050Smsmith#define MLY_CMD_MAPPED		(1<<3)		/* command has had its data mapped */
12773050Smsmith#define MLY_CMD_DATAIN		(1<<4)		/* data moves controller->system */
12873050Smsmith#define MLY_CMD_DATAOUT		(1<<5)		/* data moves system->controller */
129246713Skib#define MLY_CMD_CCB		(1<<6)		/* data is ccb. */
13064987Smsmith    u_int16_t			mc_status;	/* command completion status */
13164987Smsmith    u_int8_t			mc_sense;	/* sense data length */
13264987Smsmith    int32_t			mc_resid;	/* I/O residual count */
13364987Smsmith
13464987Smsmith    union mly_command_packet	*mc_packet;	/* our controller command */
13564987Smsmith    u_int64_t			mc_packetphys;	/* physical address of the mapped packet */
13664987Smsmith
13764987Smsmith    void			*mc_data;	/* data buffer */
13864987Smsmith    size_t			mc_length;	/* data length */
13964987Smsmith    bus_dmamap_t		mc_datamap;	/* DMA map for data */
14064987Smsmith
14164987Smsmith    void	(* mc_complete)(struct mly_command *mc);	/* completion handler */
14264987Smsmith    void	*mc_private;					/* caller-private data */
14364987Smsmith
144110479Sscottl    int				mc_timestamp;
14564987Smsmith};
14664987Smsmith
14764987Smsmith/*
14864987Smsmith * Command slot regulation.
14964987Smsmith *
15064987Smsmith * We can't use slot 0 due to the memory mailbox implementation.
15164987Smsmith */
15264987Smsmith#define MLY_SLOT_START		1
15379695Smsmith#define MLY_SLOT_MAX		(MLY_SLOT_START + MLY_MAX_COMMANDS)
15464987Smsmith
15564987Smsmith/*
15664987Smsmith * Per-controller structure.
15764987Smsmith */
15864987Smsmithstruct mly_softc {
15964987Smsmith    /* bus connections */
16064987Smsmith    device_t		mly_dev;
161130585Sphk    struct cdev *mly_dev_t;
16264987Smsmith    struct resource	*mly_regs_resource;	/* register interface window */
16364987Smsmith    int			mly_regs_rid;		/* resource ID */
16464987Smsmith    bus_space_handle_t	mly_bhandle;		/* bus space handle */
16564987Smsmith    bus_space_tag_t	mly_btag;		/* bus space tag */
16664987Smsmith    bus_dma_tag_t	mly_parent_dmat;	/* parent DMA tag */
16764987Smsmith    bus_dma_tag_t	mly_buffer_dmat;	/* data buffer/command DMA tag */
16864987Smsmith    struct resource	*mly_irq;		/* interrupt */
16964987Smsmith    int			mly_irq_rid;
17064987Smsmith    void		*mly_intr;		/* interrupt handle */
17164987Smsmith
17264987Smsmith    /* scatter/gather lists and their controller-visible mappings */
17364987Smsmith    struct mly_sg_entry	*mly_sg_table;		/* s/g lists */
17464987Smsmith    u_int32_t		mly_sg_busaddr;		/* s/g table base address in bus space */
17564987Smsmith    bus_dma_tag_t	mly_sg_dmat;		/* s/g buffer DMA tag */
17664987Smsmith    bus_dmamap_t	mly_sg_dmamap;		/* map for s/g buffers */
17764987Smsmith
17864987Smsmith    /* controller hardware interface */
17964987Smsmith    int			mly_hwif;
18064987Smsmith#define MLY_HWIF_I960RX		0
18164987Smsmith#define MLY_HWIF_STRONGARM	1
18264987Smsmith    u_int8_t		mly_doorbell_true;	/* xor map to make hardware doorbell 'true' bits into 1s */
18364987Smsmith    u_int8_t		mly_command_mailbox;	/* register offsets */
18464987Smsmith    u_int8_t		mly_status_mailbox;
18564987Smsmith    u_int8_t		mly_idbr;
18664987Smsmith    u_int8_t		mly_odbr;
18764987Smsmith    u_int8_t		mly_error_status;
18864987Smsmith    u_int8_t		mly_interrupt_status;
18964987Smsmith    u_int8_t		mly_interrupt_mask;
19064987Smsmith    struct mly_mmbox	*mly_mmbox;			/* kernel-space address of memory mailbox */
19164987Smsmith    u_int64_t		mly_mmbox_busaddr;		/* bus-space address of memory mailbox */
19264987Smsmith    bus_dma_tag_t	mly_mmbox_dmat;			/* memory mailbox DMA tag */
19364987Smsmith    bus_dmamap_t	mly_mmbox_dmamap;		/* memory mailbox DMA map */
19473050Smsmith    u_int32_t		mly_mmbox_command_index;	/* next index to use */
19573050Smsmith    u_int32_t		mly_mmbox_status_index;		/* index we next expect status at */
19664987Smsmith
19764987Smsmith    /* controller features, limits and status */
19864987Smsmith    int			mly_state;
19964987Smsmith#define	MLY_STATE_OPEN		(1<<1)
20064987Smsmith#define MLY_STATE_INTERRUPTS_ON	(1<<2)
20164987Smsmith#define MLY_STATE_MMBOX_ACTIVE	(1<<3)
20279695Smsmith#define MLY_STATE_CAM_FROZEN	(1<<4)
20364987Smsmith    struct mly_ioctl_getcontrollerinfo	*mly_controllerinfo;
20464987Smsmith    struct mly_param_controller		*mly_controllerparam;
20564987Smsmith    struct mly_btl			mly_btl[MLY_MAX_CHANNELS][MLY_MAX_TARGETS];
20664987Smsmith
20764987Smsmith    /* command management */
20879695Smsmith    struct mly_command		mly_command[MLY_MAX_COMMANDS];	/* commands */
20973050Smsmith    union mly_command_packet	*mly_packet;		/* command packets */
21073050Smsmith    bus_dma_tag_t		mly_packet_dmat;	/* packet DMA tag */
21173050Smsmith    bus_dmamap_t		mly_packetmap;		/* packet DMA map */
21273050Smsmith    u_int64_t			mly_packetphys;		/* packet array base address */
21373050Smsmith    TAILQ_HEAD(,mly_command)	mly_free;		/* commands available for reuse */
21473050Smsmith    TAILQ_HEAD(,mly_command)	mly_busy;
21573050Smsmith    TAILQ_HEAD(,mly_command)	mly_complete;		/* commands which have been returned by the controller */
21673050Smsmith    struct mly_qstat		mly_qstat[MLYQ_COUNT];	/* queue statistics */
21764987Smsmith
21864987Smsmith    /* health monitoring */
21964987Smsmith    u_int32_t			mly_event_change;	/* event status change indicator */
22064987Smsmith    u_int32_t			mly_event_counter;	/* next event for which we anticpiate status */
22164987Smsmith    u_int32_t			mly_event_waiting;	/* next event the controller will post status for */
22264987Smsmith    struct callout_handle	mly_periodic;		/* periodic event handling */
22364987Smsmith
22464987Smsmith    /* CAM connection */
22579695Smsmith    struct cam_devq		*mly_cam_devq;			/* CAM device queue */
22679695Smsmith    struct cam_sim		*mly_cam_sim[MLY_MAX_CHANNELS];	/* CAM SIMs */
22779695Smsmith    struct cam_path		*mly_cam_path;			/* rescan path */
22879695Smsmith    int				mly_cam_channels;		/* total channel count */
22964987Smsmith
23064987Smsmith    /* command-completion task */
231148853Sscottl    struct task			mly_task_complete;	/* deferred-completion task */
232110479Sscottl    int				mly_qfrzn_cnt;		/* Track simq freezes */
23364987Smsmith};
23464987Smsmith
23564987Smsmith/*
23664987Smsmith * Register access helpers.
23764987Smsmith */
23864987Smsmith#define MLY_SET_REG(sc, reg, val)	bus_space_write_1(sc->mly_btag, sc->mly_bhandle, reg, val)
23964987Smsmith#define MLY_GET_REG(sc, reg)		bus_space_read_1 (sc->mly_btag, sc->mly_bhandle, reg)
24064987Smsmith#define MLY_GET_REG2(sc, reg)		bus_space_read_2 (sc->mly_btag, sc->mly_bhandle, reg)
24164987Smsmith#define MLY_GET_REG4(sc, reg)		bus_space_read_4 (sc->mly_btag, sc->mly_bhandle, reg)
24264987Smsmith
24364987Smsmith#define MLY_SET_MBOX(sc, mbox, ptr)									\
24464987Smsmith	do {												\
24564987Smsmith	    bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox,      *((u_int32_t *)ptr));		\
24664987Smsmith	    bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox +  4, *((u_int32_t *)ptr + 1));	\
24764987Smsmith	    bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox +  8, *((u_int32_t *)ptr + 2));	\
24864987Smsmith	    bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox + 12, *((u_int32_t *)ptr + 3));	\
24964987Smsmith	} while(0);
25064987Smsmith#define MLY_GET_MBOX(sc, mbox, ptr)									\
25164987Smsmith	do {												\
25264987Smsmith	    *((u_int32_t *)ptr) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox);		\
25364987Smsmith	    *((u_int32_t *)ptr + 1) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox + 4);	\
25464987Smsmith	    *((u_int32_t *)ptr + 2) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox + 8);	\
25564987Smsmith	    *((u_int32_t *)ptr + 3) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox + 12);	\
25664987Smsmith	} while(0);
25764987Smsmith
25864987Smsmith#define MLY_IDBR_TRUE(sc, mask)								\
25964987Smsmith	((((MLY_GET_REG((sc), (sc)->mly_idbr)) ^ (sc)->mly_doorbell_true) & (mask)) == (mask))
26064987Smsmith#define MLY_ODBR_TRUE(sc, mask)								\
26164987Smsmith	((MLY_GET_REG((sc), (sc)->mly_odbr) & (mask)) == (mask))
26264987Smsmith#define MLY_ERROR_VALID(sc)								\
26364987Smsmith	((((MLY_GET_REG((sc), (sc)->mly_error_status)) ^ (sc)->mly_doorbell_true) & (MLY_MSG_EMPTY)) == 0)
26464987Smsmith
26564987Smsmith#define MLY_MASK_INTERRUPTS(sc)								\
26664987Smsmith	do {										\
26764987Smsmith	    MLY_SET_REG((sc), (sc)->mly_interrupt_mask, MLY_INTERRUPT_MASK_DISABLE);	\
26864987Smsmith	    sc->mly_state &= ~MLY_STATE_INTERRUPTS_ON;					\
26964987Smsmith	} while(0);
27064987Smsmith#define MLY_UNMASK_INTERRUPTS(sc)							\
27164987Smsmith	do {										\
27264987Smsmith	    MLY_SET_REG((sc), (sc)->mly_interrupt_mask, MLY_INTERRUPT_MASK_ENABLE);	\
27364987Smsmith	    sc->mly_state |= MLY_STATE_INTERRUPTS_ON;					\
27464987Smsmith	} while(0);
27564987Smsmith
27664987Smsmith/*
27779695Smsmith * Bus/target/logical ID-related macros.
27864987Smsmith */
27979695Smsmith#define MLY_LOGDEV_ID(sc, bus, target)	(((bus) - (sc)->mly_controllerinfo->physical_channels_present) * \
28079695Smsmith					 MLY_MAX_TARGETS + (target))
28179695Smsmith#define MLY_LOGDEV_BUS(sc, logdev)	(((logdev) / MLY_MAX_TARGETS) + \
28279695Smsmith					 (sc)->mly_controllerinfo->physical_channels_present)
28379695Smsmith#define MLY_LOGDEV_TARGET(sc, logdev)	((logdev) % MLY_MAX_TARGETS)
28479695Smsmith#define MLY_BUS_IS_VIRTUAL(sc, bus)	((bus) >= (sc)->mly_controllerinfo->physical_channels_present)
28579695Smsmith#define MLY_BUS_IS_VALID(sc, bus)	(((bus) < (sc)->mly_cam_channels) && ((sc)->mly_cam_sim[(bus)] != NULL))
28664987Smsmith
28764987Smsmith/********************************************************************************
28864987Smsmith * Queue primitives
28964987Smsmith */
29064987Smsmith
29173050Smsmith#define MLYQ_ADD(sc, qname)					\
29273050Smsmith	do {							\
29373050Smsmith	    struct mly_qstat *qs = &(sc)->mly_qstat[qname];	\
29473050Smsmith								\
29573050Smsmith	    qs->q_length++;					\
29673050Smsmith	    if (qs->q_length > qs->q_max)			\
29773050Smsmith		qs->q_max = qs->q_length;			\
29873050Smsmith	} while(0)
29964987Smsmith
30073050Smsmith#define MLYQ_REMOVE(sc, qname)    (sc)->mly_qstat[qname].q_length--
30173050Smsmith#define MLYQ_INIT(sc, qname)			\
30273050Smsmith	do {					\
30373050Smsmith	    sc->mly_qstat[qname].q_length = 0;	\
30473050Smsmith	    sc->mly_qstat[qname].q_max = 0;	\
30573050Smsmith	} while(0)
30664987Smsmith
30764987Smsmith
30873050Smsmith#define MLYQ_COMMAND_QUEUE(name, index)					\
30973050Smsmithstatic __inline void							\
31073050Smsmithmly_initq_ ## name (struct mly_softc *sc)				\
31173050Smsmith{									\
31273050Smsmith    TAILQ_INIT(&sc->mly_ ## name);					\
31373050Smsmith    MLYQ_INIT(sc, index);						\
31473050Smsmith}									\
31573050Smsmithstatic __inline void							\
31673050Smsmithmly_enqueue_ ## name (struct mly_command *mc)				\
31773050Smsmith{									\
31873050Smsmith    int		s;							\
31973050Smsmith									\
32073050Smsmith    s = splcam();							\
32173050Smsmith    TAILQ_INSERT_TAIL(&mc->mc_sc->mly_ ## name, mc, mc_link);		\
32273050Smsmith    MLYQ_ADD(mc->mc_sc, index);						\
32373050Smsmith    splx(s);								\
32473050Smsmith}									\
32573050Smsmithstatic __inline void							\
32673050Smsmithmly_requeue_ ## name (struct mly_command *mc)				\
32773050Smsmith{									\
32873050Smsmith    int		s;							\
32973050Smsmith									\
33073050Smsmith    s = splcam();							\
33173050Smsmith    TAILQ_INSERT_HEAD(&mc->mc_sc->mly_ ## name, mc, mc_link);		\
33273050Smsmith    MLYQ_ADD(mc->mc_sc, index);						\
33373050Smsmith    splx(s);								\
33473050Smsmith}									\
33573050Smsmithstatic __inline struct mly_command *					\
33673050Smsmithmly_dequeue_ ## name (struct mly_softc *sc)				\
33773050Smsmith{									\
33873050Smsmith    struct mly_command	*mc;						\
33973050Smsmith    int			s;						\
34073050Smsmith									\
34173050Smsmith    s = splcam();							\
34273050Smsmith    if ((mc = TAILQ_FIRST(&sc->mly_ ## name)) != NULL) {		\
34373050Smsmith	TAILQ_REMOVE(&sc->mly_ ## name, mc, mc_link);			\
34473050Smsmith	MLYQ_REMOVE(sc, index);						\
34573050Smsmith    }									\
34673050Smsmith    splx(s);								\
34773050Smsmith    return(mc);								\
34873050Smsmith}									\
34973050Smsmithstatic __inline void							\
35073050Smsmithmly_remove_ ## name (struct mly_command *mc)				\
35173050Smsmith{									\
35273050Smsmith    int			s;						\
35373050Smsmith									\
35473050Smsmith    s = splcam();							\
35573050Smsmith    TAILQ_REMOVE(&mc->mc_sc->mly_ ## name, mc, mc_link);		\
35673050Smsmith    MLYQ_REMOVE(mc->mc_sc, index);					\
35773050Smsmith    splx(s);								\
35873050Smsmith}									\
35973050Smsmithstruct hack
36064987Smsmith
36173050SmsmithMLYQ_COMMAND_QUEUE(free, MLYQ_FREE);
36273050SmsmithMLYQ_COMMAND_QUEUE(busy, MLYQ_BUSY);
36373050SmsmithMLYQ_COMMAND_QUEUE(complete, MLYQ_COMPLETE);
36464987Smsmith
36579695Smsmith/********************************************************************************
36679695Smsmith * space-fill a character string
36779695Smsmith */
36879695Smsmithstatic __inline void
36979695Smsmithpadstr(char *targ, char *src, int len)
37079695Smsmith{
37179695Smsmith    while (len-- > 0) {
37279695Smsmith	if (*src != 0) {
37379695Smsmith	    *targ++ = *src++;
37479695Smsmith	} else {
37579695Smsmith	    *targ++ = ' ';
37679695Smsmith	}
37779695Smsmith    }
37879695Smsmith}
379