|
|
Power 6/32 Unix version 1.2b
/* D.L.Buck and Associates, Inc. - 9/4/84
*
* COPYRIGHT NOTICE:
* Copyright c 9/4/84 - An unpublished work by
* D.L.Buck and Associates, Inc.
*
* PROPRIETARY RIGHTS NOTICE:
* All rights reserved. This document and program contains
* proprietary information of D.L.Buck and Associates,Inc.
* of San Jose, California, U.S.A., embodying confidential
* information, ideas, and expressions, no part of which
* may be reproduced, or transmitted in any form or by any
* means, electronic, mechanical, or otherwise, without
* the written permission of D.L.Buck and Associates, Inc.
*
* NAME
* bsm - multi-station bisync device driver
*
* DESCRIPTION
* This file contains the Unix system interface routines, prepared for
* UNIX Version 7, System III, System V, or BSD 4.2.
* The entry points are bsmopen, bsmclose, bsmread, bsmwrite, and
* bsmioctl. These routines are meant to be hardware-independent.
*/
#ifndef lint
static char bsm_c[] = "@(#)bscm.c 1.17 REL";
#endif
#include "../bsc/local.h"
#include "../bsc/bscio.h"
#include "../bsc/bsc.h"
#if defined v7 || defined BSD42
#define delay(x) sleep((caddr_t)&lbolt, BSCPRI)
extern int lbolt;
#endif
#if defined BSD42
#define ERRRET(x) return x
#define UCOUNT uio->uio_resid
#else
#define ERRRET(x) u.u_error = x; return
#define UCOUNT u.u_count
#endif
/***
#define DEV(dev) (minor(dev) >> 5) & 0x7
#define SUBDEV(dev) minor(dev) & 0x1f
***/
#define DEV(dev) (minor(dev) >> 4) & 0xf
#define SUBDEV(dev) minor(dev) & 0xf
extern struct state states[]; /* state table in bscpsm.c */
#ifdef NBSM
extern struct bsc bsc[]; /* device-specific information */
struct bscsub bscsubs[NVBSC*NBSM][NBSSUB];
/*
* DEVICE ADDRESSING TABLES
* For device numbers 0 - 31, the tables hold the corresponding
* EBCDIC (ebcdev) or ASCII (ascdev) address
*/
char ascdev[] = {0x20,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x48,0x49,0x5b,0x2e,0x3c,0x28,0x2b,0x21,
0x26,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,
0x51,0x52,0x5d,0x24,0x2a,0x29,0x3b,0x5e};
char ebcdev[] = {0x40,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
0xc8,0xc9,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
0xd8,0xd9,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f};
/*
* NAME
* bsmopen -- Prepare for BISYNC communications, multistation mode
* SYNOPSIS
* bsmopen (dev, flag)
* dev_t dev; minor device number:
* bits 7-5: modem port number
* bits 4-0: station number, 0-31
* int flag; unused
* ALGORITHM
* 1. Check and lock device.
* 2. If first station to open on this line, do line initialization
* 2.1 Set up defaults for ioctl-provided params
* 2.2 Set up counters and fields returned via ioctl
* 2.3 Set up miscellaneous fields for driver
* 2.4 Initialize I/O port
* 3. Wait till DSR shows
* 4. If tracing activated, awaken bstopen
*/
/* VARARGS1 */
bsmopen (dev) /* prepare for BISYNC communication */
dev_t dev;
{
register dev_t bscdev; /* modem port number */
register struct bsc *bp; /* ptr to port's bsc entry */
register int subdev; /* station number */
register struct bscsub *bpsub; /* ptr to station's bscsubs entry */
int errcode;
/* 1. Check and lock device. */
bscdev = DEV(dev);
subdev = SUBDEV(dev);
if (bscdev >= MX_NBSM || subdev >= NBSSUB){
ERRRET(ENXIO); /* no such device */
}
bp = &bsc[bscdev];
bpsub = &bscsubs[bscdev][subdev];
if ((bp->b_lock == SSLOCK) || /* line opened for point to point */
(bpsub->bs_mode != BS_FREE)) { /* subdevice busy */
ERRRET(EBUSY);
}
bpsub->bs_mode = BS_IDLE;
bpsub->bs_sema = BSC_DDONE | BSC_PDONE;
/* 2. If first station to open on this line, do line initialization */
if (++bp->b_lock == 1) { /* First one initializes */
/* 2.1 Set up defaults for ioctl-provided params */
bp->b_iocin.b_blks = BSCMBLK; /* max block size */
bp->b_hlflgs = BSCMPT; /* flags: we are multipoint */
bp->b_iocin.b_termid[0] = '\0'; /* no terminal id */
bp->b_iocin.b_hostid[0] = '\0'; /* no host id */
bp->b_iocin.b_nbid = /* max # bids */
bp->b_iocin.b_nnak = /* max # naks we will give */
bp->b_iocin.b_nretry = 15; /* max # rcv t/o's and naks */
/* we will accept */
bp->b_iocin.b_nttd = /* max # ttds we will accept */
bp->b_iocin.b_nwack = 100; /* max # wacks we will accept */
bp->b_iocin.b_nor = 30; /* max time to wait on */
/* initial rd */
/* 2.2 Set up counters and fields returned via ioctl */
bp->b_iocout.b_blks = 0; /* # blocks sent/received */
bp->b_iocout.b_flags = 0; /* flags: see definition */
bp->b_iocout.b_termid[0] = '\0';/* no terminal id */
bp->b_iocout.b_hostid[0] = '\0';/* no host id */
bp->b_iocout.b_nbid = 0; /* no bids so far */
bp->b_iocout.b_nnak = 0; /* no naks so far */
bp->b_iocout.b_nretry = 0; /* no retry so far */
bp->b_iocout.b_nttd = 0; /* no ttds so far */
bp->b_iocout.b_nwack = 0; /* no wacks so far */
bp->b_iocout.b_nor = 0; /* no overruns so far */
/* 2.3 Set up miscellaneous fields for driver */
bp->b_state = 0; /* set initial psm state*/
bp->b_mode = BSC_INIT; /* initial mode indicates */
/* haven't done any i/o yet */
bp->b_psmbsy = -1; /* no device selected */
bp->b_rxst0 = 0; /* reset l/l driver state */
bp->b_tmperr = 0; /* no temp. errors yet */
bp->b_sema = BSC_DDONE; /* driver not busy */
/* 2.4 Initialize I/O port */
errcode = bsclopn(bscdev,bp); /* device-specific init. */
if (errcode) {
bp->b_lock = 0; /* Unlock device */
ERRRET(errcode);
}
}
/* 3. Wait till DSR shows */
while (bsckdsr(bscdev,bp), !(bp->b_hlflgs & BSC_DSR) && !u.u_error)
delay(PSMTICK);
/* 4. If tracing activated, awaken bstopen */
if (bp->b_trace)
wakeup(&bp->b_trace);
if (u.u_error)
bsmclose(dev);
#if defined BSD42
return 0;
#endif
}
/*
* NAME
* bsmclose -- Terminate station processing
* SYNOPSIS
* bsmclose(dev)
* dev_t dev; minor device number:
* bits 7-5: modem port number
* bits 4-0: station number, 0-31
* ALGORITHM
* 1. Mark station done, free; decrement multistation lock
* If not last station using line, return.
* 2. Terminate PSM processing, kill receive and tracing
* 3. Turn off DTR
*/
bsmclose(dev)
dev_t dev;
{
register dev_t bscdev; /* modem port number */
register struct bsc *bp; /* ptr to port's bsc entry */
register int subdev; /* station number */
register struct bscsub *bpsub; /* ptr to station's bscsubs entry */
register long s;
bscdev = DEV(dev);
subdev = SUBDEV(dev);
bp = &bsc[bscdev];
bpsub = &bscsubs[bscdev][subdev];
/* 1. Mark station done, free; decrement multistation lock. */
/* If not last station using line, return. */
bpsub->bs_sema &= ~BSC_DBUSY;
bpsub->bs_sema |= BSC_DDONE;
bpsub->bs_mode = BS_FREE;
bpsub->bs_flags = 0;
if (--bp->b_lock) return; /* others still using the line */
s = spl8();
/* 2. Terminate PSM processing, kill receive and tracing */
bp->b_mode = BSC_CLOSED; /* mode is CLOSED */
bp->b_rclptr = (char *)0; /* terminate receive */
bstclose(bscdev); /* close trace device, too */
/* 3. Turn off DTR */
bsclcls (bscdev, bp);
splx(s);
#if defined BSD42
return 0;
#endif
}
/*
* NAME
* bsmread -- read next data block.
* SYNOPSIS
* bsmread(dev)
* dev_t dev; minor device number:
* bits 7-5: modem port number
* bits 4-0: station number, 0-31
* ALGORITHM
* 1. Check for error latch or lack of DSR.
* If either set, return EIO error.
* 2. If first activity on line, set up psm.
* 3. Based on present mode:
* 3.1 Write: error (EINVAL)
* 3.2 Idle: Synch up with psm, then go to Read mode
* 3.3 Read: If delay mode in effect, wait for err, eof, or data
* 3.3.1 Check for NO DELAY mode
* 3.3.2 Wait for full buffer, eof, or error
* 3.3.3 If EOF, chg mode to Idle, return 0 bytes read
* 3.3.4 If ERR, leave mode at Read, return -1(EIO)
* 3.3.5 Buffer full. Copy data out, set length.
* 4. Mark buffer empty, awaken psm if its sleeping
*/
#if defined BSD42
bsmread(dev,uio)
register dev_t dev;
struct uio *uio;
#else
bsmread(dev)
register dev_t dev;
#endif
{
register dev_t bscdev; /* modem port number */
register struct bsc *bp; /* ptr to port's bsc entry */
register int subdev; /* station number */
register struct bscsub *bpsub; /* ptr to station's bscsubs entry */
register int l; /* length info. */
int x; /* prty save area */
int errcode = 0; /* Error code upon return */
bscdev = DEV(dev);
subdev = SUBDEV(dev);
bp = &bsc[bscdev];
bpsub = &bscsubs[bscdev][subdev];
/* 1. Check for error latch or lack of DSR. */
/* If either set, return EIO error. */
if (!(bp->b_hlflgs & BSC_DSR) || (bpsub->bs_flags & BS_ERR)) {
if (!(bpsub->bs_flags & BS_ERR)) {
bpsub->bs_flags |= BS_ERR;
bpsub->bs_err = BSCNDSR;
}
bpsub->bs_mode = BS_IDLE;
ERRRET(EIO);
}
/* 2. If first activity on line, set up psm */
if (bp->b_mode == BSC_INIT) {
bscsetup(bscdev);
bp->b_mode = BSC_IDLE;
}
/* 3. Based on present mode: */
switch (bpsub->bs_mode)
{
/* 3.1 Write: error (EINVAL) */
case BS_WRITE:
ERRRET(EINVAL);
/* 3.2 Idle: Synch up with psm, then go to Read mode */
case BS_IDLE: /* First read call */
while (!u.u_error &&
!(bpsub->bs_sema & BSC_PDONE) &&
(bpsub->bs_mode == BS_IDLE) &&
!(bpsub->bs_flags&BS_ERR))
delay(PSMTICK); /* Synchronize */
/* Set read timeout counter */
bpsub->bs_rdflg = bp->b_iocin.b_nor*PSMTPS;
bpsub->bs_mode = BS_READ;
bpsub->bs_sema |= BSC_DBUSY;
bpsub->bs_sema &= ~BSC_DDONE; /* driver now busy */
/* 3.3 Read: If delay mode in effect, wait for err, eof, or data */
case BS_READ: /* not first read */
forceread:
x = spl8();
/* 3.3.1 Check for NO DELAY mode */
if (bpsub->bs_sema & BSC_SEENBUF) {
bpsub->bs_flags &= ~BS_FULL;
bpsub->bs_sema &= ~BSC_SEENBUF;
if (states[bp->b_state].s_type == 'd' &&
bp->b_alenb) {
bp->b_alenb = 0; /* disable alarm */
splx(x);
bscpsm(bscdev); /* awaken psm */
}
}
if ((bpsub->bs_sema & BSC_NDLY) &&
!(bpsub->bs_flags & (BS_FULL|BS_ERR|BS_LAST))) {
splx(x);
ERRRET(EAGAIN); /* Call again later */
}
/* 3.3.2 Wait for full buffer, eof, or error */
while (!(bpsub->bs_flags & (BS_FULL|BS_ERR|BS_LAST)))
sleep ((caddr_t)&bpsub->bs_flags,BSCPRI);
splx(x);
bpsub->bs_rdflg = 0; /* cancel read timeout */
/* 3.3.3 If EOF, chg mode to Idle, return 0 bytes read */
if (bpsub->bs_flags & BS_LAST) {
bpsub->bs_mode = BS_IDLE;
bp->b_hlflgs &= ~(BSC_XLAST|BSC_XTRN);
bpsub->bs_flags &= ~(BS_LAST|BSC_XTRN);
bpsub->bs_sema |= BSC_DDONE;
bpsub->bs_sema &= ~BSC_DBUSY;
goto readexit;
}
/* 3.3.4 If ERR, leave mode at Read, return -1(EIO) */
if (bpsub->bs_flags & BS_ERR) { /* error way out */
bp->b_hlflgs &= ~(BSC_XLAST|BSC_FULL|BSC_XTRN);
bpsub->bs_flags &= ~BS_FULL;
bpsub->bs_sema &= ~BSC_SEENBUF;
errcode = EIO;
goto readexit;
}
/* 3.3.5 Buffer full. Copy data out, set length. */
l = bp->b_bsize; /* buffer space occupied */
if (l > UCOUNT)
l = UCOUNT;
if (l)
#if defined BSD42
errcode = uiomove(bp->b_buffer,l,UIO_READ,uio);
#else
if (iomove (bp->b_buffer, l, B_READ))
errcode = EFAULT;
#endif
if (bpsub->bs_sema & BSC_FACK) {
bpsub->bs_sema |= BSC_SEENBUF;
goto readret;
}
/* 4. Mark buffer empty, awaken psm if its sleeping */
readexit:
bpsub->bs_flags &= ~BS_FULL;
bp->b_hlflgs &= ~BSC_FULL; /* mark buffer empty */
x = spl8();
if (states[bp->b_state].s_type == 'd' &&
bp->b_alenb) {
bp->b_alenb = 0; /* disable alarm */
splx(x);
bscpsm(bscdev); /* awaken psm */
} else splx(x);
}
readret:
#if defined BSD42
return errcode;
#else
if (errcode)
u.u_error = errcode;
#endif
}
/*
* bsmwrite -- 1) if user's length = 0 or > max block, error
* 2) if mode = read, or if error latch set, error!
* 3) if mode = init, prime the driver
* 4) if mode = idle, init, or write,
* a) set mode to write,
* b) wait till buffer empty,
* c) fill the buffer,
* d) set flag to show buffer full.
* ** The psm will reset the mode to idle after sending EOT.
*/
#if defined BSD42
bsmwrite(dev,uio)
register dev_t dev;
struct uio *uio;
#else
bsmwrite(dev)
register dev_t dev;
#endif
{
register int l; /* length given us */
register struct bsc *bp; /* ptr to bsc dev info */
register struct bscsub *bpsub; /* ptr to bsc prot dev */
register int subdev;
register dev_t bscdev;
int x; /* prty save area */
int errcode = 0; /* Error code to be returned */
subdev = SUBDEV(dev);
bscdev = DEV(dev);
bp = &bsc[bscdev];
bpsub = &bscsubs[bscdev][subdev];
/* 0. Check error latch and DSR */
if ((bpsub->bs_flags & BS_ERR) || !(bp->b_hlflgs & BSC_DSR)) {
if (!(bpsub->bs_flags & BS_ERR)) {
bpsub->bs_flags |= BS_ERR;
bpsub->bs_err = BSCNDSR;
}
ERRRET(EIO);
}
/* 1. Check length and other errors */
if ( (l = UCOUNT) == 0 || l > bp->b_iocin.b_blks) {
ERRRET(EINVAL);
}
if (bp->b_mode == BSC_INIT) {
bscsetup(bscdev);
bp->b_mode = BSC_IDLE;
}
/* 2. process according to mode */
switch (bpsub->bs_mode)
{
case BS_READ:
if ((bpsub->bs_sema & BSC_FACK) &&
(bpsub->bs_sema & BSC_SEENBUF)) {
bpsub->bs_flags &= ~BS_FULL;
bpsub->bs_sema &= ~BSC_SEENBUF;
bpsub->bs_mode = BS_WRITE;
goto casewrite;
}
if (bpsub->bs_rdflg == 0) {
ERRRET(EINVAL); /* oops - can't read now! */
} else {
bpsub->bs_sema &= ~BSC_DBUSY;
bpsub->bs_sema |= BSC_DDONE;
bpsub->bs_rdflg = 1;
while (bpsub->bs_mode == BS_READ &&
!(bpsub->bs_flags & BS_ERR))
delay(PSMTICK);
}
bpsub->bs_mode = BS_IDLE;
case BS_IDLE:
if (bpsub->bs_flags & BS_FULL) {
ERRRET(EINVAL); /* Caller needs to read */
}
while (!(bpsub->bs_sema & BSC_PDONE) &&
!(bpsub->bs_flags & BS_ERR))
delay(PSMTICK); /* Synchronize */
bpsub->bs_mode = BS_WRITE;
bpsub->bs_flags &= ~BS_ERR; /* reset possible err */
bpsub->bs_sema |= BSC_DBUSY;
bpsub->bs_sema &= ~BSC_DDONE; /* driver now busy */
casewrite:
case BS_WRITE:
x = spl8();
while ((bpsub->bs_flags & BS_FULL) && /*wait til empty */
(!(bpsub->bs_flags & BS_ERR)))
sleep ((caddr_t)&bpsub->bs_flags,BSCPRI);
splx(x);
if (bpsub->bs_flags & BS_ERR){
bp->b_hlflgs &= ~(BSC_FULL|BSC_XLAST|BSC_XTRN);
bpsub->bs_flags &= ~(BS_FULL|BS_LAST|BSC_XTRN);
bpsub->bs_mode = BS_IDLE;
ERRRET(EIO);
}
/* copy data to buffer */
#if defined BSD42
errcode = uiomove(bpsub->bs_buf,l,UIO_WRITE,uio);
#else
if (iomove (bpsub->bs_buf, l, B_WRITE))
errcode = EFAULT;
#endif
bpsub->bs_size = l; /*save size */
x = spl8();
bpsub->bs_flags |= BS_FULL; /* bufr now full */
if (states[bp->b_state].s_type == 'd' &&
bp->b_alenb) { /* decision wait? */
bp->b_alenb = 0; /* disable pto */
splx(x);
bscpsm(bscdev); /* wake 'em up */
} else splx(x);
if (bpsub->bs_flags & BS_LAST) { /* if last block, wait */
x = spl8();
while ((bpsub->bs_flags & BS_FULL) && /*wait til empty*/
(!(bpsub->bs_flags & BS_ERR))) /*no error*/
sleep ((caddr_t)&bpsub->bs_flags, BSCPRI);
splx(x);
if (bpsub->bs_flags & BS_ERR){
errcode = EIO;
} else {
bpsub->bs_sema |= BSC_DDONE;
bpsub->bs_sema &= ~BSC_DBUSY;
bpsub->bs_mode = BS_IDLE;
}
bp->b_hlflgs &= ~(BSC_XLAST|BSC_FULL|BSC_XTRN);
bpsub->bs_flags &= ~(BS_LAST|BS_FULL|BSC_XTRN);
}
}
#if defined BSD42
return errcode;
#else
if (errcode)
u.u_error = errcode;
#endif
}
/* bsmioctl -- set options or get counter values
* Depending on cmd:
* BSCGET - copy b_iocout to user's area
* BSCSET - copy user's values to b_iocin (set stuff)
* BSCTRNSP - set transparent mode flag
* BSCNTRNS - reset transparent mode flag
* BSCSOH - set send SOH flag
* BSCNSOH - turn off SOH flag
* BSCLAST - set send last flag
* BSCID - determine port id number
*/
/*VARARGS3*/
bsmioctl(dev, cmd, arg)
dev_t dev;
struct bscio *arg;
{
register struct bsc *bp; /* ptr to dev info */
register struct bscsub *bpsub; /* ptr to port info */
struct bscio tmp; /* temp struct for chk'g user params*/
register int x;
register int subdev;
register dev_t bscdev;
int y,errcode = 0;
dev = minor(dev);
subdev = SUBDEV(dev);
bscdev = DEV(dev);
bp = &bsc[bscdev];
bpsub = &bscsubs[bscdev][subdev];
if (cmd != BSCGET && cmd != BSCSET) { /* if write op, wait on buf */
x = spl8();
while (bpsub->bs_mode == BS_WRITE && bpsub->bs_flags & BS_FULL)
sleep ((caddr_t)&bpsub->bs_flags, BSCPRI);
splx(x);
}
if ((cmd == BSCSET) && (bp->b_lock != 1)) {/* only 1st can set modes */
ERRRET(EINVAL);
}
switch (cmd) {
case BSCGET:
x = spl8();
bp->b_iocout.b_flags = bpsub->bs_err;
#if defined BSD42
bcopy((caddr_t)&bp->b_iocout, arg, sizeof bp->b_iocout);
#else
if (copyout(&bp->b_iocout, arg, sizeof bp->b_iocout))
errcode = EFAULT;
#endif
bpsub->bs_err = 0;
bp->b_iocout.b_flags = 0;
if (bpsub->bs_flags & BS_ERR) {
bpsub->bs_flags &= ~(BS_ERR|BS_LAST|BS_FULL|BSC_XTRN);
bpsub->bs_sema &= ~BSC_DBUSY;
bpsub->bs_sema |= BSC_DDONE;
bpsub->bs_mode = BS_IDLE;
}
splx(x);
break;
case BSCSET:
if (bpsub->bs_mode == BS_READ || bpsub->bs_mode == BS_WRITE) {
errcode = EINVAL; /* can't set if active */
break;
}
#if defined BSD42
bcopy(arg, (caddr_t)&tmp, sizeof tmp);
#else
if (copyin (arg, &tmp, sizeof tmp)) {
errcode = EFAULT;
break;
}
#endif
if (tmp.b_blks > BSCMBLK || /* block size too big? */
tmp.b_blks > sizeof bpsub->bs_buf) {
errcode = EINVAL;
break;
}
bcopy (/*from*/&tmp, /*to*/&bp->b_iocin, sizeof tmp);
x = spl8(); /* *** protect hlflgs */
bp->b_hlflgs &= ~BSC_UFLAGS; /* throw out old user flags */
bp->b_hlflgs |= (BSCMPT|(tmp.b_flags & BSC_UFLAGS));
splx(x); /* *** end protection */
bscparam(bscdev); /* redo parameters */
break;
case BSCTRNSP:
x = spl8(); /* *** protect bsflgs */
bpsub->bs_flags |= BSC_XTRN; /* set transparent mode */
splx(x); /* *** end protection */
break;
case BSCNTRNS:
x = spl8(); /* *** protect bsflgs */
bpsub->bs_flags &= ~BSC_XTRN; /* reset transp. mode */
splx(x); /* *** end protection */
break;
case BSCSOH:
x = spl8(); /* *** protect bsflags */
bpsub->bs_flags |= BSC_XSOH; /* set send SOH flag */
splx(x); /* *** end protection */
break;
case BSCNSOH:
x = spl8(); /* *** protect bsflags */
bpsub->bs_flags &= ~BSC_XSOH; /* clear send SOH flag*/
splx(x); /* end protection */
break;
case BSCLAST:
x = spl8(); /* *** protect bsflags */
bpsub->bs_flags |= BS_LAST; /* set send last blk flag */
splx(x); /* end protection */
break;
case BSCNDLY:
x = spl8(); /* protect bs flags */
bpsub->bs_sema |= BSC_NDLY;
splx(x);
break;
case BSCID:
y = ((bp->b_hlflgs & BSCASCII)?ascdev:ebcdev)[subdev];
#if defined BSD42
bcopy((caddr_t)&y, (int *)arg, sizeof y);
#else
copyout(&y,(int *)arg,sizeof y);
#endif
break;
case BSCFACK:
x = spl8();
bpsub->bs_sema |= BSC_FACK;
splx(x);
break;
default:
errcode = EINVAL;
break;
}
#if defined BSD42
return errcode;
#else
if (errcode)
u.u_error = errcode;
#endif
}
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.