123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163 |
- /*
- * Copyright IBM Corp. 2004, 2007
- * Authors: Belinda Thompson (belindat@us.ibm.com)
- * Andy Richter (richtera@us.ibm.com)
- * Peter Tiedemann (ptiedem@de.ibm.com)
- */
- /*
- This module exports functions to be used by CCS:
- EXPORT_SYMBOL(ctc_mpc_alloc_channel);
- EXPORT_SYMBOL(ctc_mpc_establish_connectivity);
- EXPORT_SYMBOL(ctc_mpc_dealloc_ch);
- EXPORT_SYMBOL(ctc_mpc_flow_control);
- */
- #undef DEBUG
- #undef DEBUGDATA
- #undef DEBUGCCW
- #define KMSG_COMPONENT "ctcm"
- #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/errno.h>
- #include <linux/types.h>
- #include <linux/interrupt.h>
- #include <linux/timer.h>
- #include <linux/sched.h>
- #include <linux/signal.h>
- #include <linux/string.h>
- #include <linux/proc_fs.h>
- #include <linux/ip.h>
- #include <linux/if_arp.h>
- #include <linux/tcp.h>
- #include <linux/skbuff.h>
- #include <linux/ctype.h>
- #include <linux/netdevice.h>
- #include <net/dst.h>
- #include <linux/io.h> /* instead of <asm/io.h> ok ? */
- #include <asm/ccwdev.h>
- #include <asm/ccwgroup.h>
- #include <linux/bitops.h> /* instead of <asm/bitops.h> ok ? */
- #include <linux/uaccess.h> /* instead of <asm/uaccess.h> ok ? */
- #include <linux/wait.h>
- #include <linux/moduleparam.h>
- #include <asm/idals.h>
- #include "ctcm_main.h"
- #include "ctcm_mpc.h"
- #include "ctcm_fsms.h"
- static const struct xid2 init_xid = {
- .xid2_type_id = XID_FM2,
- .xid2_len = 0x45,
- .xid2_adj_id = 0,
- .xid2_rlen = 0x31,
- .xid2_resv1 = 0,
- .xid2_flag1 = 0,
- .xid2_fmtt = 0,
- .xid2_flag4 = 0x80,
- .xid2_resv2 = 0,
- .xid2_tgnum = 0,
- .xid2_sender_id = 0,
- .xid2_flag2 = 0,
- .xid2_option = XID2_0,
- .xid2_resv3 = "\x00",
- .xid2_resv4 = 0,
- .xid2_dlc_type = XID2_READ_SIDE,
- .xid2_resv5 = 0,
- .xid2_mpc_flag = 0,
- .xid2_resv6 = 0,
- .xid2_buf_len = (MPC_BUFSIZE_DEFAULT - 35),
- };
- static const struct th_header thnorm = {
- .th_seg = 0x00,
- .th_ch_flag = TH_IS_XID,
- .th_blk_flag = TH_DATA_IS_XID,
- .th_is_xid = 0x01,
- .th_seq_num = 0x00000000,
- };
- static const struct th_header thdummy = {
- .th_seg = 0x00,
- .th_ch_flag = 0x00,
- .th_blk_flag = TH_DATA_IS_XID,
- .th_is_xid = 0x01,
- .th_seq_num = 0x00000000,
- };
- /*
- * Definition of one MPC group
- */
- /*
- * Compatibility macros for busy handling
- * of network devices.
- */
- static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb);
- /*
- * MPC Group state machine actions (static prototypes)
- */
- static void mpc_action_nop(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_go_ready(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg);
- static void mpc_action_timeout(fsm_instance *fi, int event, void *arg);
- static int mpc_validate_xid(struct mpcg_info *mpcginfo);
- static void mpc_action_yside_xid(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_doxid0(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_xside_xid(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_rcvd_xid0(fsm_instance *fsm, int event, void *arg);
- static void mpc_action_rcvd_xid7(fsm_instance *fsm, int event, void *arg);
- #ifdef DEBUGDATA
- /*-------------------------------------------------------------------*
- * Dump buffer format *
- * *
- *--------------------------------------------------------------------*/
- void ctcmpc_dumpit(char *buf, int len)
- {
- __u32 ct, sw, rm, dup;
- char *ptr, *rptr;
- char tbuf[82], tdup[82];
- char addr[22];
- char boff[12];
- char bhex[82], duphex[82];
- char basc[40];
- sw = 0;
- rptr = ptr = buf;
- rm = 16;
- duphex[0] = 0x00;
- dup = 0;
- for (ct = 0; ct < len; ct++, ptr++, rptr++) {
- if (sw == 0) {
- sprintf(addr, "%16.16llx", (__u64)rptr);
- sprintf(boff, "%4.4X", (__u32)ct);
- bhex[0] = '\0';
- basc[0] = '\0';
- }
- if ((sw == 4) || (sw == 12))
- strcat(bhex, " ");
- if (sw == 8)
- strcat(bhex, " ");
- sprintf(tbuf, "%2.2llX", (__u64)*ptr);
- tbuf[2] = '\0';
- strcat(bhex, tbuf);
- if ((0 != isprint(*ptr)) && (*ptr >= 0x20))
- basc[sw] = *ptr;
- else
- basc[sw] = '.';
- basc[sw+1] = '\0';
- sw++;
- rm--;
- if (sw != 16)
- continue;
- if ((strcmp(duphex, bhex)) != 0) {
- if (dup != 0) {
- sprintf(tdup,
- "Duplicate as above to %s", addr);
- ctcm_pr_debug(" --- %s ---\n",
- tdup);
- }
- ctcm_pr_debug(" %s (+%s) : %s [%s]\n",
- addr, boff, bhex, basc);
- dup = 0;
- strcpy(duphex, bhex);
- } else
- dup++;
- sw = 0;
- rm = 16;
- } /* endfor */
- if (sw != 0) {
- for ( ; rm > 0; rm--, sw++) {
- if ((sw == 4) || (sw == 12))
- strcat(bhex, " ");
- if (sw == 8)
- strcat(bhex, " ");
- strcat(bhex, " ");
- strcat(basc, " ");
- }
- if (dup != 0) {
- sprintf(tdup, "Duplicate as above to %s", addr);
- ctcm_pr_debug(" --- %s ---\n", tdup);
- }
- ctcm_pr_debug(" %s (+%s) : %s [%s]\n",
- addr, boff, bhex, basc);
- } else {
- if (dup >= 1) {
- sprintf(tdup, "Duplicate as above to %s", addr);
- ctcm_pr_debug(" --- %s ---\n", tdup);
- }
- if (dup != 0) {
- ctcm_pr_debug(" %s (+%s) : %s [%s]\n",
- addr, boff, bhex, basc);
- }
- }
- return;
- } /* end of ctcmpc_dumpit */
- #endif
- #ifdef DEBUGDATA
- /*
- * Dump header and first 16 bytes of an sk_buff for debugging purposes.
- *
- * skb The sk_buff to dump.
- * offset Offset relative to skb-data, where to start the dump.
- */
- void ctcmpc_dump_skb(struct sk_buff *skb, int offset)
- {
- __u8 *p = skb->data;
- struct th_header *header;
- struct pdu *pheader;
- int bl = skb->len;
- int i;
- if (p == NULL)
- return;
- p += offset;
- header = (struct th_header *)p;
- ctcm_pr_debug("dump:\n");
- ctcm_pr_debug("skb len=%d \n", skb->len);
- if (skb->len > 2) {
- switch (header->th_ch_flag) {
- case TH_HAS_PDU:
- break;
- case 0x00:
- case TH_IS_XID:
- if ((header->th_blk_flag == TH_DATA_IS_XID) &&
- (header->th_is_xid == 0x01))
- goto dumpth;
- case TH_SWEEP_REQ:
- goto dumpth;
- case TH_SWEEP_RESP:
- goto dumpth;
- default:
- break;
- }
- pheader = (struct pdu *)p;
- ctcm_pr_debug("pdu->offset: %d hex: %04x\n",
- pheader->pdu_offset, pheader->pdu_offset);
- ctcm_pr_debug("pdu->flag : %02x\n", pheader->pdu_flag);
- ctcm_pr_debug("pdu->proto : %02x\n", pheader->pdu_proto);
- ctcm_pr_debug("pdu->seq : %02x\n", pheader->pdu_seq);
- goto dumpdata;
- dumpth:
- ctcm_pr_debug("th->seg : %02x\n", header->th_seg);
- ctcm_pr_debug("th->ch : %02x\n", header->th_ch_flag);
- ctcm_pr_debug("th->blk_flag: %02x\n", header->th_blk_flag);
- ctcm_pr_debug("th->type : %s\n",
- (header->th_is_xid) ? "DATA" : "XID");
- ctcm_pr_debug("th->seqnum : %04x\n", header->th_seq_num);
- }
- dumpdata:
- if (bl > 32)
- bl = 32;
- ctcm_pr_debug("data: ");
- for (i = 0; i < bl; i++)
- ctcm_pr_debug("%02x%s", *p++, (i % 16) ? " " : "\n");
- ctcm_pr_debug("\n");
- }
- #endif
- static struct net_device *ctcmpc_get_dev(int port_num)
- {
- char device[20];
- struct net_device *dev;
- struct ctcm_priv *priv;
- sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num);
- dev = __dev_get_by_name(&init_net, device);
- if (dev == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s: Device not found by name: %s",
- CTCM_FUNTAIL, device);
- return NULL;
- }
- priv = dev->ml_priv;
- if (priv == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): dev->ml_priv is NULL",
- CTCM_FUNTAIL, device);
- return NULL;
- }
- if (priv->mpcg == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): priv->mpcg is NULL",
- CTCM_FUNTAIL, device);
- return NULL;
- }
- return dev;
- }
- /*
- * ctc_mpc_alloc_channel
- * (exported interface)
- *
- * Device Initialization :
- * ACTPATH driven IO operations
- */
- int ctc_mpc_alloc_channel(int port_num, void (*callback)(int, int))
- {
- struct net_device *dev;
- struct mpc_group *grp;
- struct ctcm_priv *priv;
- dev = ctcmpc_get_dev(port_num);
- if (dev == NULL)
- return 1;
- priv = dev->ml_priv;
- grp = priv->mpcg;
- grp->allochanfunc = callback;
- grp->port_num = port_num;
- grp->port_persist = 1;
- CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_INFO,
- "%s(%s): state=%s",
- CTCM_FUNTAIL, dev->name, fsm_getstate_str(grp->fsm));
- switch (fsm_getstate(grp->fsm)) {
- case MPCG_STATE_INOP:
- /* Group is in the process of terminating */
- grp->alloc_called = 1;
- break;
- case MPCG_STATE_RESET:
- /* MPC Group will transition to state */
- /* MPCG_STATE_XID2INITW iff the minimum number */
- /* of 1 read and 1 write channel have successfully*/
- /* activated */
- /*fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW);*/
- if (callback)
- grp->send_qllc_disc = 1;
- case MPCG_STATE_XID0IOWAIT:
- fsm_deltimer(&grp->timer);
- grp->outstanding_xid2 = 0;
- grp->outstanding_xid7 = 0;
- grp->outstanding_xid7_p2 = 0;
- grp->saved_xid2 = NULL;
- if (callback)
- ctcm_open(dev);
- fsm_event(priv->fsm, DEV_EVENT_START, dev);
- break;
- case MPCG_STATE_READY:
- /* XID exchanges completed after PORT was activated */
- /* Link station already active */
- /* Maybe timing issue...retry callback */
- grp->allocchan_callback_retries++;
- if (grp->allocchan_callback_retries < 4) {
- if (grp->allochanfunc)
- grp->allochanfunc(grp->port_num,
- grp->group_max_buflen);
- } else {
- /* there are problems...bail out */
- /* there may be a state mismatch so restart */
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- grp->allocchan_callback_retries = 0;
- }
- break;
- }
- return 0;
- }
- EXPORT_SYMBOL(ctc_mpc_alloc_channel);
- /*
- * ctc_mpc_establish_connectivity
- * (exported interface)
- */
- void ctc_mpc_establish_connectivity(int port_num,
- void (*callback)(int, int, int))
- {
- struct net_device *dev;
- struct mpc_group *grp;
- struct ctcm_priv *priv;
- struct channel *rch, *wch;
- dev = ctcmpc_get_dev(port_num);
- if (dev == NULL)
- return;
- priv = dev->ml_priv;
- grp = priv->mpcg;
- rch = priv->channel[CTCM_READ];
- wch = priv->channel[CTCM_WRITE];
- CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_INFO,
- "%s(%s): state=%s",
- CTCM_FUNTAIL, dev->name, fsm_getstate_str(grp->fsm));
- grp->estconnfunc = callback;
- grp->port_num = port_num;
- switch (fsm_getstate(grp->fsm)) {
- case MPCG_STATE_READY:
- /* XID exchanges completed after PORT was activated */
- /* Link station already active */
- /* Maybe timing issue...retry callback */
- fsm_deltimer(&grp->timer);
- grp->estconn_callback_retries++;
- if (grp->estconn_callback_retries < 4) {
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, 0,
- grp->group_max_buflen);
- grp->estconnfunc = NULL;
- }
- } else {
- /* there are problems...bail out */
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- grp->estconn_callback_retries = 0;
- }
- break;
- case MPCG_STATE_INOP:
- case MPCG_STATE_RESET:
- /* MPC Group is not ready to start XID - min num of */
- /* 1 read and 1 write channel have not been acquired*/
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): REJECTED - inactive channels",
- CTCM_FUNTAIL, dev->name);
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, -1, 0);
- grp->estconnfunc = NULL;
- }
- break;
- case MPCG_STATE_XID2INITW:
- /* alloc channel was called but no XID exchange */
- /* has occurred. initiate xside XID exchange */
- /* make sure yside XID0 processing has not started */
- if ((fsm_getstate(rch->fsm) > CH_XID0_PENDING) ||
- (fsm_getstate(wch->fsm) > CH_XID0_PENDING)) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): ABORT - PASSIVE XID",
- CTCM_FUNTAIL, dev->name);
- break;
- }
- grp->send_qllc_disc = 1;
- fsm_newstate(grp->fsm, MPCG_STATE_XID0IOWAIT);
- fsm_deltimer(&grp->timer);
- fsm_addtimer(&grp->timer, MPC_XID_TIMEOUT_VALUE,
- MPCG_EVENT_TIMER, dev);
- grp->outstanding_xid7 = 0;
- grp->outstanding_xid7_p2 = 0;
- grp->saved_xid2 = NULL;
- if ((rch->in_mpcgroup) &&
- (fsm_getstate(rch->fsm) == CH_XID0_PENDING))
- fsm_event(grp->fsm, MPCG_EVENT_XID0DO, rch);
- else {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): RX-%s not ready for ACTIVE XID0",
- CTCM_FUNTAIL, dev->name, rch->id);
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, -1, 0);
- grp->estconnfunc = NULL;
- }
- fsm_deltimer(&grp->timer);
- goto done;
- }
- if ((wch->in_mpcgroup) &&
- (fsm_getstate(wch->fsm) == CH_XID0_PENDING))
- fsm_event(grp->fsm, MPCG_EVENT_XID0DO, wch);
- else {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): WX-%s not ready for ACTIVE XID0",
- CTCM_FUNTAIL, dev->name, wch->id);
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, -1, 0);
- grp->estconnfunc = NULL;
- }
- fsm_deltimer(&grp->timer);
- goto done;
- }
- break;
- case MPCG_STATE_XID0IOWAIT:
- /* already in active XID negotiations */
- default:
- break;
- }
- done:
- CTCM_PR_DEBUG("Exit %s()\n", __func__);
- return;
- }
- EXPORT_SYMBOL(ctc_mpc_establish_connectivity);
- /*
- * ctc_mpc_dealloc_ch
- * (exported interface)
- */
- void ctc_mpc_dealloc_ch(int port_num)
- {
- struct net_device *dev;
- struct ctcm_priv *priv;
- struct mpc_group *grp;
- dev = ctcmpc_get_dev(port_num);
- if (dev == NULL)
- return;
- priv = dev->ml_priv;
- grp = priv->mpcg;
- CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_DEBUG,
- "%s: %s: refcount = %d\n",
- CTCM_FUNTAIL, dev->name, netdev_refcnt_read(dev));
- fsm_deltimer(&priv->restart_timer);
- grp->channels_terminating = 0;
- fsm_deltimer(&grp->timer);
- grp->allochanfunc = NULL;
- grp->estconnfunc = NULL;
- grp->port_persist = 0;
- grp->send_qllc_disc = 0;
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- ctcm_close(dev);
- return;
- }
- EXPORT_SYMBOL(ctc_mpc_dealloc_ch);
- /*
- * ctc_mpc_flow_control
- * (exported interface)
- */
- void ctc_mpc_flow_control(int port_num, int flowc)
- {
- struct ctcm_priv *priv;
- struct mpc_group *grp;
- struct net_device *dev;
- struct channel *rch;
- int mpcg_state;
- dev = ctcmpc_get_dev(port_num);
- if (dev == NULL)
- return;
- priv = dev->ml_priv;
- grp = priv->mpcg;
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG,
- "%s: %s: flowc = %d",
- CTCM_FUNTAIL, dev->name, flowc);
- rch = priv->channel[CTCM_READ];
- mpcg_state = fsm_getstate(grp->fsm);
- switch (flowc) {
- case 1:
- if (mpcg_state == MPCG_STATE_FLOWC)
- break;
- if (mpcg_state == MPCG_STATE_READY) {
- if (grp->flow_off_called == 1)
- grp->flow_off_called = 0;
- else
- fsm_newstate(grp->fsm, MPCG_STATE_FLOWC);
- break;
- }
- break;
- case 0:
- if (mpcg_state == MPCG_STATE_FLOWC) {
- fsm_newstate(grp->fsm, MPCG_STATE_READY);
- /* ensure any data that has accumulated */
- /* on the io_queue will now be sen t */
- tasklet_schedule(&rch->ch_tasklet);
- }
- /* possible race condition */
- if (mpcg_state == MPCG_STATE_READY) {
- grp->flow_off_called = 1;
- break;
- }
- break;
- }
- }
- EXPORT_SYMBOL(ctc_mpc_flow_control);
- static int mpc_send_qllc_discontact(struct net_device *);
- /*
- * helper function of ctcmpc_unpack_skb
- */
- static void mpc_rcvd_sweep_resp(struct mpcg_info *mpcginfo)
- {
- struct channel *rch = mpcginfo->ch;
- struct net_device *dev = rch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- struct channel *ch = priv->channel[CTCM_WRITE];
- CTCM_PR_DEBUG("%s: ch=0x%p id=%s\n", __func__, ch, ch->id);
- CTCM_D3_DUMP((char *)mpcginfo->sweep, TH_SWEEP_LENGTH);
- grp->sweep_rsp_pend_num--;
- if ((grp->sweep_req_pend_num == 0) &&
- (grp->sweep_rsp_pend_num == 0)) {
- fsm_deltimer(&ch->sweep_timer);
- grp->in_sweep = 0;
- rch->th_seq_num = 0x00;
- ch->th_seq_num = 0x00;
- ctcm_clear_busy_do(dev);
- }
- kfree(mpcginfo);
- return;
- }
- /*
- * helper function of mpc_rcvd_sweep_req
- * which is a helper of ctcmpc_unpack_skb
- */
- static void ctcmpc_send_sweep_resp(struct channel *rch)
- {
- struct net_device *dev = rch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- struct th_sweep *header;
- struct sk_buff *sweep_skb;
- struct channel *ch = priv->channel[CTCM_WRITE];
- CTCM_PR_DEBUG("%s: ch=0x%p id=%s\n", __func__, rch, rch->id);
- sweep_skb = __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC | GFP_DMA);
- if (sweep_skb == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): sweep_skb allocation ERROR\n",
- CTCM_FUNTAIL, rch->id);
- goto done;
- }
- header = kmalloc(sizeof(struct th_sweep), gfp_type());
- if (!header) {
- dev_kfree_skb_any(sweep_skb);
- goto done;
- }
- header->th.th_seg = 0x00 ;
- header->th.th_ch_flag = TH_SWEEP_RESP;
- header->th.th_blk_flag = 0x00;
- header->th.th_is_xid = 0x00;
- header->th.th_seq_num = 0x00;
- header->sw.th_last_seq = ch->th_seq_num;
- memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH);
- kfree(header);
- netif_trans_update(dev);
- skb_queue_tail(&ch->sweep_queue, sweep_skb);
- fsm_addtimer(&ch->sweep_timer, 100, CTC_EVENT_RSWEEP_TIMER, ch);
- return;
- done:
- grp->in_sweep = 0;
- ctcm_clear_busy_do(dev);
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- return;
- }
- /*
- * helper function of ctcmpc_unpack_skb
- */
- static void mpc_rcvd_sweep_req(struct mpcg_info *mpcginfo)
- {
- struct channel *rch = mpcginfo->ch;
- struct net_device *dev = rch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- struct channel *ch = priv->channel[CTCM_WRITE];
- if (do_debug)
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG,
- " %s(): ch=0x%p id=%s\n", __func__, ch, ch->id);
- if (grp->in_sweep == 0) {
- grp->in_sweep = 1;
- ctcm_test_and_set_busy(dev);
- grp->sweep_req_pend_num = grp->active_channels[CTCM_READ];
- grp->sweep_rsp_pend_num = grp->active_channels[CTCM_READ];
- }
- CTCM_D3_DUMP((char *)mpcginfo->sweep, TH_SWEEP_LENGTH);
- grp->sweep_req_pend_num--;
- ctcmpc_send_sweep_resp(ch);
- kfree(mpcginfo);
- return;
- }
- /*
- * MPC Group Station FSM definitions
- */
- static const char *mpcg_event_names[] = {
- [MPCG_EVENT_INOP] = "INOP Condition",
- [MPCG_EVENT_DISCONC] = "Discontact Received",
- [MPCG_EVENT_XID0DO] = "Channel Active - Start XID",
- [MPCG_EVENT_XID2] = "XID2 Received",
- [MPCG_EVENT_XID2DONE] = "XID0 Complete",
- [MPCG_EVENT_XID7DONE] = "XID7 Complete",
- [MPCG_EVENT_TIMER] = "XID Setup Timer",
- [MPCG_EVENT_DOIO] = "XID DoIO",
- };
- static const char *mpcg_state_names[] = {
- [MPCG_STATE_RESET] = "Reset",
- [MPCG_STATE_INOP] = "INOP",
- [MPCG_STATE_XID2INITW] = "Passive XID- XID0 Pending Start",
- [MPCG_STATE_XID2INITX] = "Passive XID- XID0 Pending Complete",
- [MPCG_STATE_XID7INITW] = "Passive XID- XID7 Pending P1 Start",
- [MPCG_STATE_XID7INITX] = "Passive XID- XID7 Pending P2 Complete",
- [MPCG_STATE_XID0IOWAIT] = "Active XID- XID0 Pending Start",
- [MPCG_STATE_XID0IOWAIX] = "Active XID- XID0 Pending Complete",
- [MPCG_STATE_XID7INITI] = "Active XID- XID7 Pending Start",
- [MPCG_STATE_XID7INITZ] = "Active XID- XID7 Pending Complete ",
- [MPCG_STATE_XID7INITF] = "XID - XID7 Complete ",
- [MPCG_STATE_FLOWC] = "FLOW CONTROL ON",
- [MPCG_STATE_READY] = "READY",
- };
- /*
- * The MPC Group Station FSM
- * 22 events
- */
- static const fsm_node mpcg_fsm[] = {
- { MPCG_STATE_RESET, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_INOP, MPCG_EVENT_INOP, mpc_action_nop },
- { MPCG_STATE_FLOWC, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_READY, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_READY, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID2INITW, MPCG_EVENT_XID0DO, mpc_action_doxid0 },
- { MPCG_STATE_XID2INITW, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 },
- { MPCG_STATE_XID2INITW, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID2INITW, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID2INITW, MPCG_EVENT_DOIO, mpc_action_yside_xid },
- { MPCG_STATE_XID2INITX, MPCG_EVENT_XID0DO, mpc_action_doxid0 },
- { MPCG_STATE_XID2INITX, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 },
- { MPCG_STATE_XID2INITX, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID2INITX, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID2INITX, MPCG_EVENT_DOIO, mpc_action_yside_xid },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_XID2DONE, mpc_action_doxid7 },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_XID7DONE, mpc_action_doxid7 },
- { MPCG_STATE_XID7INITW, MPCG_EVENT_DOIO, mpc_action_yside_xid },
- { MPCG_STATE_XID7INITX, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_XID7INITX, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 },
- { MPCG_STATE_XID7INITX, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID7INITX, MPCG_EVENT_XID7DONE, mpc_action_doxid7 },
- { MPCG_STATE_XID7INITX, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID7INITX, MPCG_EVENT_DOIO, mpc_action_yside_xid },
- { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_XID0DO, mpc_action_doxid0 },
- { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 },
- { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID0IOWAIT, MPCG_EVENT_DOIO, mpc_action_xside_xid },
- { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_XID0DO, mpc_action_doxid0 },
- { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_XID2, mpc_action_rcvd_xid0 },
- { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID0IOWAIX, MPCG_EVENT_DOIO, mpc_action_xside_xid },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_XID2DONE, mpc_action_doxid7 },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_XID7DONE, mpc_action_doxid7 },
- { MPCG_STATE_XID7INITI, MPCG_EVENT_DOIO, mpc_action_xside_xid },
- { MPCG_STATE_XID7INITZ, MPCG_EVENT_XID2, mpc_action_rcvd_xid7 },
- { MPCG_STATE_XID7INITZ, MPCG_EVENT_XID7DONE, mpc_action_doxid7 },
- { MPCG_STATE_XID7INITZ, MPCG_EVENT_DISCONC, mpc_action_discontact },
- { MPCG_STATE_XID7INITZ, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID7INITZ, MPCG_EVENT_TIMER, mpc_action_timeout },
- { MPCG_STATE_XID7INITZ, MPCG_EVENT_DOIO, mpc_action_xside_xid },
- { MPCG_STATE_XID7INITF, MPCG_EVENT_INOP, mpc_action_go_inop },
- { MPCG_STATE_XID7INITF, MPCG_EVENT_XID7DONE, mpc_action_go_ready },
- };
- static int mpcg_fsm_len = ARRAY_SIZE(mpcg_fsm);
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_go_ready(fsm_instance *fsm, int event, void *arg)
- {
- struct net_device *dev = arg;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- if (grp == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): No MPC group",
- CTCM_FUNTAIL, dev->name);
- return;
- }
- fsm_deltimer(&grp->timer);
- if (grp->saved_xid2->xid2_flag2 == 0x40) {
- priv->xid->xid2_flag2 = 0x00;
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, 1,
- grp->group_max_buflen);
- grp->estconnfunc = NULL;
- } else if (grp->allochanfunc)
- grp->send_qllc_disc = 1;
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): fails",
- CTCM_FUNTAIL, dev->name);
- return;
- }
- grp->port_persist = 1;
- grp->out_of_sequence = 0;
- grp->estconn_called = 0;
- tasklet_hi_schedule(&grp->mpc_tasklet2);
- return;
- }
- /*
- * helper of ctcm_init_netdevice
- * CTCM_PROTO_MPC only
- */
- void mpc_group_ready(unsigned long adev)
- {
- struct net_device *dev = (struct net_device *)adev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- struct channel *ch = NULL;
- if (grp == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): No MPC group",
- CTCM_FUNTAIL, dev->name);
- return;
- }
- CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_NOTICE,
- "%s: %s: GROUP TRANSITIONED TO READY, maxbuf = %d\n",
- CTCM_FUNTAIL, dev->name, grp->group_max_buflen);
- fsm_newstate(grp->fsm, MPCG_STATE_READY);
- /* Put up a read on the channel */
- ch = priv->channel[CTCM_READ];
- ch->pdu_seq = 0;
- CTCM_PR_DBGDATA("ctcmpc: %s() ToDCM_pdu_seq= %08x\n" ,
- __func__, ch->pdu_seq);
- ctcmpc_chx_rxidle(ch->fsm, CTC_EVENT_START, ch);
- /* Put the write channel in idle state */
- ch = priv->channel[CTCM_WRITE];
- if (ch->collect_len > 0) {
- spin_lock(&ch->collect_lock);
- ctcm_purge_skb_queue(&ch->collect_queue);
- ch->collect_len = 0;
- spin_unlock(&ch->collect_lock);
- }
- ctcm_chx_txidle(ch->fsm, CTC_EVENT_START, ch);
- ctcm_clear_busy(dev);
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, 0,
- grp->group_max_buflen);
- grp->estconnfunc = NULL;
- } else if (grp->allochanfunc)
- grp->allochanfunc(grp->port_num, grp->group_max_buflen);
- grp->send_qllc_disc = 1;
- grp->changed_side = 0;
- return;
- }
- /*
- * Increment the MPC Group Active Channel Counts
- * helper of dev_action (called from channel fsm)
- */
- void mpc_channel_action(struct channel *ch, int direction, int action)
- {
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- if (grp == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): No MPC group",
- CTCM_FUNTAIL, dev->name);
- return;
- }
- CTCM_PR_DEBUG("enter %s: ch=0x%p id=%s\n", __func__, ch, ch->id);
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_NOTICE,
- "%s: %i / Grp:%s total_channels=%i, active_channels: "
- "read=%i, write=%i\n", __func__, action,
- fsm_getstate_str(grp->fsm), grp->num_channel_paths,
- grp->active_channels[CTCM_READ],
- grp->active_channels[CTCM_WRITE]);
- if ((action == MPC_CHANNEL_ADD) && (ch->in_mpcgroup == 0)) {
- grp->num_channel_paths++;
- grp->active_channels[direction]++;
- grp->outstanding_xid2++;
- ch->in_mpcgroup = 1;
- if (ch->xid_skb != NULL)
- dev_kfree_skb_any(ch->xid_skb);
- ch->xid_skb = __dev_alloc_skb(MPC_BUFSIZE_DEFAULT,
- GFP_ATOMIC | GFP_DMA);
- if (ch->xid_skb == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): Couldn't alloc ch xid_skb\n",
- CTCM_FUNTAIL, dev->name);
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- return;
- }
- ch->xid_skb_data = ch->xid_skb->data;
- ch->xid_th = (struct th_header *)ch->xid_skb->data;
- skb_put(ch->xid_skb, TH_HEADER_LENGTH);
- ch->xid = (struct xid2 *)skb_tail_pointer(ch->xid_skb);
- skb_put(ch->xid_skb, XID2_LENGTH);
- ch->xid_id = skb_tail_pointer(ch->xid_skb);
- ch->xid_skb->data = ch->xid_skb_data;
- skb_reset_tail_pointer(ch->xid_skb);
- ch->xid_skb->len = 0;
- memcpy(skb_put(ch->xid_skb, grp->xid_skb->len),
- grp->xid_skb->data,
- grp->xid_skb->len);
- ch->xid->xid2_dlc_type =
- ((CHANNEL_DIRECTION(ch->flags) == CTCM_READ)
- ? XID2_READ_SIDE : XID2_WRITE_SIDE);
- if (CHANNEL_DIRECTION(ch->flags) == CTCM_WRITE)
- ch->xid->xid2_buf_len = 0x00;
- ch->xid_skb->data = ch->xid_skb_data;
- skb_reset_tail_pointer(ch->xid_skb);
- ch->xid_skb->len = 0;
- fsm_newstate(ch->fsm, CH_XID0_PENDING);
- if ((grp->active_channels[CTCM_READ] > 0) &&
- (grp->active_channels[CTCM_WRITE] > 0) &&
- (fsm_getstate(grp->fsm) < MPCG_STATE_XID2INITW)) {
- fsm_newstate(grp->fsm, MPCG_STATE_XID2INITW);
- CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_NOTICE,
- "%s: %s: MPC GROUP CHANNELS ACTIVE\n",
- __func__, dev->name);
- }
- } else if ((action == MPC_CHANNEL_REMOVE) &&
- (ch->in_mpcgroup == 1)) {
- ch->in_mpcgroup = 0;
- grp->num_channel_paths--;
- grp->active_channels[direction]--;
- if (ch->xid_skb != NULL)
- dev_kfree_skb_any(ch->xid_skb);
- ch->xid_skb = NULL;
- if (grp->channels_terminating)
- goto done;
- if (((grp->active_channels[CTCM_READ] == 0) &&
- (grp->active_channels[CTCM_WRITE] > 0))
- || ((grp->active_channels[CTCM_WRITE] == 0) &&
- (grp->active_channels[CTCM_READ] > 0)))
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- }
- done:
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG,
- "exit %s: %i / Grp:%s total_channels=%i, active_channels: "
- "read=%i, write=%i\n", __func__, action,
- fsm_getstate_str(grp->fsm), grp->num_channel_paths,
- grp->active_channels[CTCM_READ],
- grp->active_channels[CTCM_WRITE]);
- CTCM_PR_DEBUG("exit %s: ch=0x%p id=%s\n", __func__, ch, ch->id);
- }
- /**
- * Unpack a just received skb and hand it over to
- * upper layers.
- * special MPC version of unpack_skb.
- *
- * ch The channel where this skb has been received.
- * pskb The received skb.
- */
- static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
- {
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- struct pdu *curr_pdu;
- struct mpcg_info *mpcginfo;
- struct th_header *header = NULL;
- struct th_sweep *sweep = NULL;
- int pdu_last_seen = 0;
- __u32 new_len;
- struct sk_buff *skb;
- int skblen;
- int sendrc = 0;
- CTCM_PR_DEBUG("ctcmpc enter: %s() %s cp:%i ch:%s\n",
- __func__, dev->name, smp_processor_id(), ch->id);
- header = (struct th_header *)pskb->data;
- if ((header->th_seg == 0) &&
- (header->th_ch_flag == 0) &&
- (header->th_blk_flag == 0) &&
- (header->th_seq_num == 0))
- /* nothing for us */ goto done;
- CTCM_PR_DBGDATA("%s: th_header\n", __func__);
- CTCM_D3_DUMP((char *)header, TH_HEADER_LENGTH);
- CTCM_PR_DBGDATA("%s: pskb len: %04x \n", __func__, pskb->len);
- pskb->dev = dev;
- pskb->ip_summed = CHECKSUM_UNNECESSARY;
- skb_pull(pskb, TH_HEADER_LENGTH);
- if (likely(header->th_ch_flag == TH_HAS_PDU)) {
- CTCM_PR_DBGDATA("%s: came into th_has_pdu\n", __func__);
- if ((fsm_getstate(grp->fsm) == MPCG_STATE_FLOWC) ||
- ((fsm_getstate(grp->fsm) == MPCG_STATE_READY) &&
- (header->th_seq_num != ch->th_seq_num + 1) &&
- (ch->th_seq_num != 0))) {
- /* This is NOT the next segment *
- * we are not the correct race winner *
- * go away and let someone else win *
- * BUT..this only applies if xid negot *
- * is done *
- */
- grp->out_of_sequence += 1;
- __skb_push(pskb, TH_HEADER_LENGTH);
- skb_queue_tail(&ch->io_queue, pskb);
- CTCM_PR_DBGDATA("%s: th_seq_num expect:%08x "
- "got:%08x\n", __func__,
- ch->th_seq_num + 1, header->th_seq_num);
- return;
- }
- grp->out_of_sequence = 0;
- ch->th_seq_num = header->th_seq_num;
- CTCM_PR_DBGDATA("ctcmpc: %s() FromVTAM_th_seq=%08x\n",
- __func__, ch->th_seq_num);
- if (unlikely(fsm_getstate(grp->fsm) != MPCG_STATE_READY))
- goto done;
- while ((pskb->len > 0) && !pdu_last_seen) {
- curr_pdu = (struct pdu *)pskb->data;
- CTCM_PR_DBGDATA("%s: pdu_header\n", __func__);
- CTCM_D3_DUMP((char *)pskb->data, PDU_HEADER_LENGTH);
- CTCM_PR_DBGDATA("%s: pskb len: %04x \n",
- __func__, pskb->len);
- skb_pull(pskb, PDU_HEADER_LENGTH);
- if (curr_pdu->pdu_flag & PDU_LAST)
- pdu_last_seen = 1;
- if (curr_pdu->pdu_flag & PDU_CNTL)
- pskb->protocol = htons(ETH_P_SNAP);
- else
- pskb->protocol = htons(ETH_P_SNA_DIX);
- if ((pskb->len <= 0) || (pskb->len > ch->max_bufsize)) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): Dropping packet with "
- "illegal siize %d",
- CTCM_FUNTAIL, dev->name, pskb->len);
- priv->stats.rx_dropped++;
- priv->stats.rx_length_errors++;
- goto done;
- }
- skb_reset_mac_header(pskb);
- new_len = curr_pdu->pdu_offset;
- CTCM_PR_DBGDATA("%s: new_len: %04x \n",
- __func__, new_len);
- if ((new_len == 0) || (new_len > pskb->len)) {
- /* should never happen */
- /* pskb len must be hosed...bail out */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): non valid pdu_offset: %04x",
- /* "data may be lost", */
- CTCM_FUNTAIL, dev->name, new_len);
- goto done;
- }
- skb = __dev_alloc_skb(new_len+4, GFP_ATOMIC);
- if (!skb) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): MEMORY allocation error",
- CTCM_FUNTAIL, dev->name);
- priv->stats.rx_dropped++;
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
- }
- memcpy(skb_put(skb, new_len), pskb->data, new_len);
- skb_reset_mac_header(skb);
- skb->dev = pskb->dev;
- skb->protocol = pskb->protocol;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- *((__u32 *) skb_push(skb, 4)) = ch->pdu_seq;
- ch->pdu_seq++;
- if (do_debug_data) {
- ctcm_pr_debug("%s: ToDCM_pdu_seq= %08x\n",
- __func__, ch->pdu_seq);
- ctcm_pr_debug("%s: skb:%0lx "
- "skb len: %d \n", __func__,
- (unsigned long)skb, skb->len);
- ctcm_pr_debug("%s: up to 32 bytes "
- "of pdu_data sent\n", __func__);
- ctcmpc_dump32((char *)skb->data, skb->len);
- }
- skblen = skb->len;
- sendrc = netif_rx(skb);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skblen;
- skb_pull(pskb, new_len); /* point to next PDU */
- }
- } else {
- mpcginfo = kmalloc(sizeof(struct mpcg_info), gfp_type());
- if (mpcginfo == NULL)
- goto done;
- mpcginfo->ch = ch;
- mpcginfo->th = header;
- mpcginfo->skb = pskb;
- CTCM_PR_DEBUG("%s: Not PDU - may be control pkt\n",
- __func__);
- /* it's a sweep? */
- sweep = (struct th_sweep *)pskb->data;
- mpcginfo->sweep = sweep;
- if (header->th_ch_flag == TH_SWEEP_REQ)
- mpc_rcvd_sweep_req(mpcginfo);
- else if (header->th_ch_flag == TH_SWEEP_RESP)
- mpc_rcvd_sweep_resp(mpcginfo);
- else if (header->th_blk_flag == TH_DATA_IS_XID) {
- struct xid2 *thisxid = (struct xid2 *)pskb->data;
- skb_pull(pskb, XID2_LENGTH);
- mpcginfo->xid = thisxid;
- fsm_event(grp->fsm, MPCG_EVENT_XID2, mpcginfo);
- } else if (header->th_blk_flag == TH_DISCONTACT)
- fsm_event(grp->fsm, MPCG_EVENT_DISCONC, mpcginfo);
- else if (header->th_seq_num != 0) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): control pkt expected\n",
- CTCM_FUNTAIL, dev->name);
- priv->stats.rx_dropped++;
- /* mpcginfo only used for non-data transfers */
- kfree(mpcginfo);
- if (do_debug_data)
- ctcmpc_dump_skb(pskb, -8);
- }
- }
- done:
- dev_kfree_skb_any(pskb);
- if (sendrc == NET_RX_DROP) {
- dev_warn(&dev->dev,
- "The network backlog for %s is exceeded, "
- "package dropped\n", __func__);
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- }
- CTCM_PR_DEBUG("exit %s: %s: ch=0x%p id=%s\n",
- __func__, dev->name, ch, ch->id);
- }
- /**
- * tasklet helper for mpc's skb unpacking.
- *
- * ch The channel to work on.
- * Allow flow control back pressure to occur here.
- * Throttling back channel can result in excessive
- * channel inactivity and system deact of channel
- */
- void ctcmpc_bh(unsigned long thischan)
- {
- struct channel *ch = (struct channel *)thischan;
- struct sk_buff *skb;
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- CTCM_PR_DEBUG("%s cp:%i enter: %s() %s\n",
- dev->name, smp_processor_id(), __func__, ch->id);
- /* caller has requested driver to throttle back */
- while ((fsm_getstate(grp->fsm) != MPCG_STATE_FLOWC) &&
- (skb = skb_dequeue(&ch->io_queue))) {
- ctcmpc_unpack_skb(ch, skb);
- if (grp->out_of_sequence > 20) {
- /* assume data loss has occurred if */
- /* missing seq_num for extended */
- /* period of time */
- grp->out_of_sequence = 0;
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- break;
- }
- if (skb == skb_peek(&ch->io_queue))
- break;
- }
- CTCM_PR_DEBUG("exit %s: %s: ch=0x%p id=%s\n",
- __func__, dev->name, ch, ch->id);
- return;
- }
- /*
- * MPC Group Initializations
- */
- struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv)
- {
- struct mpc_group *grp;
- CTCM_DBF_TEXT_(MPC_SETUP, CTC_DBF_INFO,
- "Enter %s(%p)", CTCM_FUNTAIL, priv);
- grp = kzalloc(sizeof(struct mpc_group), GFP_KERNEL);
- if (grp == NULL)
- return NULL;
- grp->fsm = init_fsm("mpcg", mpcg_state_names, mpcg_event_names,
- MPCG_NR_STATES, MPCG_NR_EVENTS, mpcg_fsm,
- mpcg_fsm_len, GFP_KERNEL);
- if (grp->fsm == NULL) {
- kfree(grp);
- return NULL;
- }
- fsm_newstate(grp->fsm, MPCG_STATE_RESET);
- fsm_settimer(grp->fsm, &grp->timer);
- grp->xid_skb =
- __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC | GFP_DMA);
- if (grp->xid_skb == NULL) {
- kfree_fsm(grp->fsm);
- kfree(grp);
- return NULL;
- }
- /* base xid for all channels in group */
- grp->xid_skb_data = grp->xid_skb->data;
- grp->xid_th = (struct th_header *)grp->xid_skb->data;
- memcpy(skb_put(grp->xid_skb, TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
- grp->xid = (struct xid2 *)skb_tail_pointer(grp->xid_skb);
- memcpy(skb_put(grp->xid_skb, XID2_LENGTH), &init_xid, XID2_LENGTH);
- grp->xid->xid2_adj_id = jiffies | 0xfff00000;
- grp->xid->xid2_sender_id = jiffies;
- grp->xid_id = skb_tail_pointer(grp->xid_skb);
- memcpy(skb_put(grp->xid_skb, 4), "VTAM", 4);
- grp->rcvd_xid_skb =
- __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC|GFP_DMA);
- if (grp->rcvd_xid_skb == NULL) {
- kfree_fsm(grp->fsm);
- dev_kfree_skb(grp->xid_skb);
- kfree(grp);
- return NULL;
- }
- grp->rcvd_xid_data = grp->rcvd_xid_skb->data;
- grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data;
- memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
- grp->saved_xid2 = NULL;
- priv->xid = grp->xid;
- priv->mpcg = grp;
- return grp;
- }
- /*
- * The MPC Group Station FSM
- */
- /*
- * MPC Group Station FSM actions
- * CTCM_PROTO_MPC only
- */
- /**
- * NOP action for statemachines
- */
- static void mpc_action_nop(fsm_instance *fi, int event, void *arg)
- {
- }
- /*
- * invoked when the device transitions to dev_stopped
- * MPC will stop each individual channel if a single XID failure
- * occurs, or will intitiate all channels be stopped if a GROUP
- * level failure occurs.
- */
- static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg)
- {
- struct net_device *dev = arg;
- struct ctcm_priv *priv;
- struct mpc_group *grp;
- struct channel *wch;
- CTCM_PR_DEBUG("Enter %s: %s\n", __func__, dev->name);
- priv = dev->ml_priv;
- grp = priv->mpcg;
- grp->flow_off_called = 0;
- fsm_deltimer(&grp->timer);
- if (grp->channels_terminating)
- return;
- grp->channels_terminating = 1;
- grp->saved_state = fsm_getstate(grp->fsm);
- fsm_newstate(grp->fsm, MPCG_STATE_INOP);
- if (grp->saved_state > MPCG_STATE_XID7INITF)
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_NOTICE,
- "%s(%s): MPC GROUP INOPERATIVE",
- CTCM_FUNTAIL, dev->name);
- if ((grp->saved_state != MPCG_STATE_RESET) ||
- /* dealloc_channel has been called */
- (grp->port_persist == 0))
- fsm_deltimer(&priv->restart_timer);
- wch = priv->channel[CTCM_WRITE];
- switch (grp->saved_state) {
- case MPCG_STATE_RESET:
- case MPCG_STATE_INOP:
- case MPCG_STATE_XID2INITW:
- case MPCG_STATE_XID0IOWAIT:
- case MPCG_STATE_XID2INITX:
- case MPCG_STATE_XID7INITW:
- case MPCG_STATE_XID7INITX:
- case MPCG_STATE_XID0IOWAIX:
- case MPCG_STATE_XID7INITI:
- case MPCG_STATE_XID7INITZ:
- case MPCG_STATE_XID7INITF:
- break;
- case MPCG_STATE_FLOWC:
- case MPCG_STATE_READY:
- default:
- tasklet_hi_schedule(&wch->ch_disc_tasklet);
- }
- grp->xid2_tgnum = 0;
- grp->group_max_buflen = 0; /*min of all received */
- grp->outstanding_xid2 = 0;
- grp->outstanding_xid7 = 0;
- grp->outstanding_xid7_p2 = 0;
- grp->saved_xid2 = NULL;
- grp->xidnogood = 0;
- grp->changed_side = 0;
- grp->rcvd_xid_skb->data = grp->rcvd_xid_data;
- skb_reset_tail_pointer(grp->rcvd_xid_skb);
- grp->rcvd_xid_skb->len = 0;
- grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data;
- memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH), &thnorm,
- TH_HEADER_LENGTH);
- if (grp->send_qllc_disc == 1) {
- grp->send_qllc_disc = 0;
- mpc_send_qllc_discontact(dev);
- }
- /* DO NOT issue DEV_EVENT_STOP directly out of this code */
- /* This can result in INOP of VTAM PU due to halting of */
- /* outstanding IO which causes a sense to be returned */
- /* Only about 3 senses are allowed and then IOS/VTAM will*/
- /* become unreachable without manual intervention */
- if ((grp->port_persist == 1) || (grp->alloc_called)) {
- grp->alloc_called = 0;
- fsm_deltimer(&priv->restart_timer);
- fsm_addtimer(&priv->restart_timer, 500, DEV_EVENT_RESTART, dev);
- fsm_newstate(grp->fsm, MPCG_STATE_RESET);
- if (grp->saved_state > MPCG_STATE_XID7INITF)
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_ALWAYS,
- "%s(%s): MPC GROUP RECOVERY SCHEDULED",
- CTCM_FUNTAIL, dev->name);
- } else {
- fsm_deltimer(&priv->restart_timer);
- fsm_addtimer(&priv->restart_timer, 500, DEV_EVENT_STOP, dev);
- fsm_newstate(grp->fsm, MPCG_STATE_RESET);
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_ALWAYS,
- "%s(%s): NO MPC GROUP RECOVERY ATTEMPTED",
- CTCM_FUNTAIL, dev->name);
- }
- }
- /**
- * Handle mpc group action timeout.
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- *
- * fi An instance of an mpc_group fsm.
- * event The event, just happened.
- * arg Generic pointer, casted from net_device * upon call.
- */
- static void mpc_action_timeout(fsm_instance *fi, int event, void *arg)
- {
- struct net_device *dev = arg;
- struct ctcm_priv *priv;
- struct mpc_group *grp;
- struct channel *wch;
- struct channel *rch;
- priv = dev->ml_priv;
- grp = priv->mpcg;
- wch = priv->channel[CTCM_WRITE];
- rch = priv->channel[CTCM_READ];
- switch (fsm_getstate(grp->fsm)) {
- case MPCG_STATE_XID2INITW:
- /* Unless there is outstanding IO on the */
- /* channel just return and wait for ATTN */
- /* interrupt to begin XID negotiations */
- if ((fsm_getstate(rch->fsm) == CH_XID0_PENDING) &&
- (fsm_getstate(wch->fsm) == CH_XID0_PENDING))
- break;
- default:
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- }
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG,
- "%s: dev=%s exit",
- CTCM_FUNTAIL, dev->name);
- return;
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- void mpc_action_discontact(fsm_instance *fi, int event, void *arg)
- {
- struct mpcg_info *mpcginfo = arg;
- struct channel *ch = mpcginfo->ch;
- struct net_device *dev;
- struct ctcm_priv *priv;
- struct mpc_group *grp;
- if (ch) {
- dev = ch->netdev;
- if (dev) {
- priv = dev->ml_priv;
- if (priv) {
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_NOTICE,
- "%s: %s: %s\n",
- CTCM_FUNTAIL, dev->name, ch->id);
- grp = priv->mpcg;
- grp->send_qllc_disc = 1;
- fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- }
- }
- }
- return;
- }
- /*
- * MPC Group Station - not part of FSM
- * CTCM_PROTO_MPC only
- * called from add_channel in ctcm_main.c
- */
- void mpc_action_send_discontact(unsigned long thischan)
- {
- int rc;
- struct channel *ch = (struct channel *)thischan;
- unsigned long saveflags = 0;
- spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
- rc = ccw_device_start(ch->cdev, &ch->ccw[15],
- (unsigned long)ch, 0xff, 0);
- spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
- if (rc != 0) {
- ctcm_ccw_check_rc(ch, rc, (char *)__func__);
- }
- return;
- }
- /*
- * helper function of mpc FSM
- * CTCM_PROTO_MPC only
- * mpc_action_rcvd_xid7
- */
- static int mpc_validate_xid(struct mpcg_info *mpcginfo)
- {
- struct channel *ch = mpcginfo->ch;
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- struct xid2 *xid = mpcginfo->xid;
- int rc = 0;
- __u64 our_id = 0;
- __u64 their_id = 0;
- int len = TH_HEADER_LENGTH + PDU_HEADER_LENGTH;
- CTCM_PR_DEBUG("Enter %s: xid=%p\n", __func__, xid);
- if (xid == NULL) {
- rc = 1;
- /* XID REJECTED: xid == NULL */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): xid = NULL",
- CTCM_FUNTAIL, ch->id);
- goto done;
- }
- CTCM_D3_DUMP((char *)xid, XID2_LENGTH);
- /*the received direction should be the opposite of ours */
- if (((CHANNEL_DIRECTION(ch->flags) == CTCM_READ) ? XID2_WRITE_SIDE :
- XID2_READ_SIDE) != xid->xid2_dlc_type) {
- rc = 2;
- /* XID REJECTED: r/w channel pairing mismatch */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): r/w channel pairing mismatch",
- CTCM_FUNTAIL, ch->id);
- goto done;
- }
- if (xid->xid2_dlc_type == XID2_READ_SIDE) {
- CTCM_PR_DEBUG("%s: grpmaxbuf:%d xid2buflen:%d\n", __func__,
- grp->group_max_buflen, xid->xid2_buf_len);
- if (grp->group_max_buflen == 0 || grp->group_max_buflen >
- xid->xid2_buf_len - len)
- grp->group_max_buflen = xid->xid2_buf_len - len;
- }
- if (grp->saved_xid2 == NULL) {
- grp->saved_xid2 =
- (struct xid2 *)skb_tail_pointer(grp->rcvd_xid_skb);
- memcpy(skb_put(grp->rcvd_xid_skb,
- XID2_LENGTH), xid, XID2_LENGTH);
- grp->rcvd_xid_skb->data = grp->rcvd_xid_data;
- skb_reset_tail_pointer(grp->rcvd_xid_skb);
- grp->rcvd_xid_skb->len = 0;
- /* convert two 32 bit numbers into 1 64 bit for id compare */
- our_id = (__u64)priv->xid->xid2_adj_id;
- our_id = our_id << 32;
- our_id = our_id + priv->xid->xid2_sender_id;
- their_id = (__u64)xid->xid2_adj_id;
- their_id = their_id << 32;
- their_id = their_id + xid->xid2_sender_id;
- /* lower id assume the xside role */
- if (our_id < their_id) {
- grp->roll = XSIDE;
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_NOTICE,
- "%s(%s): WE HAVE LOW ID - TAKE XSIDE",
- CTCM_FUNTAIL, ch->id);
- } else {
- grp->roll = YSIDE;
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_NOTICE,
- "%s(%s): WE HAVE HIGH ID - TAKE YSIDE",
- CTCM_FUNTAIL, ch->id);
- }
- } else {
- if (xid->xid2_flag4 != grp->saved_xid2->xid2_flag4) {
- rc = 3;
- /* XID REJECTED: xid flag byte4 mismatch */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): xid flag byte4 mismatch",
- CTCM_FUNTAIL, ch->id);
- }
- if (xid->xid2_flag2 == 0x40) {
- rc = 4;
- /* XID REJECTED - xid NOGOOD */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): xid NOGOOD",
- CTCM_FUNTAIL, ch->id);
- }
- if (xid->xid2_adj_id != grp->saved_xid2->xid2_adj_id) {
- rc = 5;
- /* XID REJECTED - Adjacent Station ID Mismatch */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): Adjacent Station ID Mismatch",
- CTCM_FUNTAIL, ch->id);
- }
- if (xid->xid2_sender_id != grp->saved_xid2->xid2_sender_id) {
- rc = 6;
- /* XID REJECTED - Sender Address Mismatch */
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): Sender Address Mismatch",
- CTCM_FUNTAIL, ch->id);
- }
- }
- done:
- if (rc) {
- dev_warn(&dev->dev,
- "The XID used in the MPC protocol is not valid, "
- "rc = %d\n", rc);
- priv->xid->xid2_flag2 = 0x40;
- grp->saved_xid2->xid2_flag2 = 0x40;
- }
- return rc;
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_side_xid(fsm_instance *fsm, void *arg, int side)
- {
- struct channel *ch = arg;
- int rc = 0;
- int gotlock = 0;
- unsigned long saveflags = 0; /* avoids compiler warning with
- spin_unlock_irqrestore */
- CTCM_PR_DEBUG("Enter %s: cp=%i ch=0x%p id=%s\n",
- __func__, smp_processor_id(), ch, ch->id);
- if (ctcm_checkalloc_buffer(ch))
- goto done;
- /*
- * skb data-buffer referencing:
- */
- ch->trans_skb->data = ch->trans_skb_data;
- skb_reset_tail_pointer(ch->trans_skb);
- ch->trans_skb->len = 0;
- /* result of the previous 3 statements is NOT always
- * already set after ctcm_checkalloc_buffer
- * because of possible reuse of the trans_skb
- */
- memset(ch->trans_skb->data, 0, 16);
- ch->rcvd_xid_th = (struct th_header *)ch->trans_skb_data;
- /* check is main purpose here: */
- skb_put(ch->trans_skb, TH_HEADER_LENGTH);
- ch->rcvd_xid = (struct xid2 *)skb_tail_pointer(ch->trans_skb);
- /* check is main purpose here: */
- skb_put(ch->trans_skb, XID2_LENGTH);
- ch->rcvd_xid_id = skb_tail_pointer(ch->trans_skb);
- /* cleanup back to startpoint */
- ch->trans_skb->data = ch->trans_skb_data;
- skb_reset_tail_pointer(ch->trans_skb);
- ch->trans_skb->len = 0;
- /* non-checking rewrite of above skb data-buffer referencing: */
- /*
- memset(ch->trans_skb->data, 0, 16);
- ch->rcvd_xid_th = (struct th_header *)ch->trans_skb_data;
- ch->rcvd_xid = (struct xid2 *)(ch->trans_skb_data + TH_HEADER_LENGTH);
- ch->rcvd_xid_id = ch->trans_skb_data + TH_HEADER_LENGTH + XID2_LENGTH;
- */
- ch->ccw[8].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[8].count = 0;
- ch->ccw[8].cda = 0x00;
- if (!(ch->xid_th && ch->xid && ch->xid_id))
- CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_INFO,
- "%s(%s): xid_th=%p, xid=%p, xid_id=%p",
- CTCM_FUNTAIL, ch->id, ch->xid_th, ch->xid, ch->xid_id);
- if (side == XSIDE) {
- /* mpc_action_xside_xid */
- if (ch->xid_th == NULL)
- goto done;
- ch->ccw[9].cmd_code = CCW_CMD_WRITE;
- ch->ccw[9].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[9].count = TH_HEADER_LENGTH;
- ch->ccw[9].cda = virt_to_phys(ch->xid_th);
- if (ch->xid == NULL)
- goto done;
- ch->ccw[10].cmd_code = CCW_CMD_WRITE;
- ch->ccw[10].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[10].count = XID2_LENGTH;
- ch->ccw[10].cda = virt_to_phys(ch->xid);
- ch->ccw[11].cmd_code = CCW_CMD_READ;
- ch->ccw[11].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[11].count = TH_HEADER_LENGTH;
- ch->ccw[11].cda = virt_to_phys(ch->rcvd_xid_th);
- ch->ccw[12].cmd_code = CCW_CMD_READ;
- ch->ccw[12].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[12].count = XID2_LENGTH;
- ch->ccw[12].cda = virt_to_phys(ch->rcvd_xid);
- ch->ccw[13].cmd_code = CCW_CMD_READ;
- ch->ccw[13].cda = virt_to_phys(ch->rcvd_xid_id);
- } else { /* side == YSIDE : mpc_action_yside_xid */
- ch->ccw[9].cmd_code = CCW_CMD_READ;
- ch->ccw[9].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[9].count = TH_HEADER_LENGTH;
- ch->ccw[9].cda = virt_to_phys(ch->rcvd_xid_th);
- ch->ccw[10].cmd_code = CCW_CMD_READ;
- ch->ccw[10].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[10].count = XID2_LENGTH;
- ch->ccw[10].cda = virt_to_phys(ch->rcvd_xid);
- if (ch->xid_th == NULL)
- goto done;
- ch->ccw[11].cmd_code = CCW_CMD_WRITE;
- ch->ccw[11].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[11].count = TH_HEADER_LENGTH;
- ch->ccw[11].cda = virt_to_phys(ch->xid_th);
- if (ch->xid == NULL)
- goto done;
- ch->ccw[12].cmd_code = CCW_CMD_WRITE;
- ch->ccw[12].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[12].count = XID2_LENGTH;
- ch->ccw[12].cda = virt_to_phys(ch->xid);
- if (ch->xid_id == NULL)
- goto done;
- ch->ccw[13].cmd_code = CCW_CMD_WRITE;
- ch->ccw[13].cda = virt_to_phys(ch->xid_id);
- }
- ch->ccw[13].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->ccw[13].count = 4;
- ch->ccw[14].cmd_code = CCW_CMD_NOOP;
- ch->ccw[14].flags = CCW_FLAG_SLI;
- ch->ccw[14].count = 0;
- ch->ccw[14].cda = 0;
- CTCM_CCW_DUMP((char *)&ch->ccw[8], sizeof(struct ccw1) * 7);
- CTCM_D3_DUMP((char *)ch->xid_th, TH_HEADER_LENGTH);
- CTCM_D3_DUMP((char *)ch->xid, XID2_LENGTH);
- CTCM_D3_DUMP((char *)ch->xid_id, 4);
- if (!in_irq()) {
- /* Such conditional locking is a known problem for
- * sparse because its static undeterministic.
- * Warnings should be ignored here. */
- spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
- gotlock = 1;
- }
- fsm_addtimer(&ch->timer, 5000 , CTC_EVENT_TIMER, ch);
- rc = ccw_device_start(ch->cdev, &ch->ccw[8],
- (unsigned long)ch, 0xff, 0);
- if (gotlock) /* see remark above about conditional locking */
- spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
- if (rc != 0) {
- ctcm_ccw_check_rc(ch, rc,
- (side == XSIDE) ? "x-side XID" : "y-side XID");
- }
- done:
- CTCM_PR_DEBUG("Exit %s: ch=0x%p id=%s\n",
- __func__, ch, ch->id);
- return;
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_xside_xid(fsm_instance *fsm, int event, void *arg)
- {
- mpc_action_side_xid(fsm, arg, XSIDE);
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_yside_xid(fsm_instance *fsm, int event, void *arg)
- {
- mpc_action_side_xid(fsm, arg, YSIDE);
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_doxid0(fsm_instance *fsm, int event, void *arg)
- {
- struct channel *ch = arg;
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- CTCM_PR_DEBUG("Enter %s: cp=%i ch=0x%p id=%s\n",
- __func__, smp_processor_id(), ch, ch->id);
- if (ch->xid == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): ch->xid == NULL",
- CTCM_FUNTAIL, dev->name);
- return;
- }
- fsm_newstate(ch->fsm, CH_XID0_INPROGRESS);
- ch->xid->xid2_option = XID2_0;
- switch (fsm_getstate(grp->fsm)) {
- case MPCG_STATE_XID2INITW:
- case MPCG_STATE_XID2INITX:
- ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD;
- break;
- case MPCG_STATE_XID0IOWAIT:
- case MPCG_STATE_XID0IOWAIX:
- ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL;
- break;
- }
- fsm_event(grp->fsm, MPCG_EVENT_DOIO, ch);
- return;
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg)
- {
- struct net_device *dev = arg;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = NULL;
- int direction;
- int send = 0;
- if (priv)
- grp = priv->mpcg;
- if (grp == NULL)
- return;
- for (direction = CTCM_READ; direction <= CTCM_WRITE; direction++) {
- struct channel *ch = priv->channel[direction];
- struct xid2 *thisxid = ch->xid;
- ch->xid_skb->data = ch->xid_skb_data;
- skb_reset_tail_pointer(ch->xid_skb);
- ch->xid_skb->len = 0;
- thisxid->xid2_option = XID2_7;
- send = 0;
- /* xid7 phase 1 */
- if (grp->outstanding_xid7_p2 > 0) {
- if (grp->roll == YSIDE) {
- if (fsm_getstate(ch->fsm) == CH_XID7_PENDING1) {
- fsm_newstate(ch->fsm, CH_XID7_PENDING2);
- ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD;
- memcpy(skb_put(ch->xid_skb,
- TH_HEADER_LENGTH),
- &thdummy, TH_HEADER_LENGTH);
- send = 1;
- }
- } else if (fsm_getstate(ch->fsm) < CH_XID7_PENDING2) {
- fsm_newstate(ch->fsm, CH_XID7_PENDING2);
- ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL;
- memcpy(skb_put(ch->xid_skb,
- TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
- send = 1;
- }
- } else {
- /* xid7 phase 2 */
- if (grp->roll == YSIDE) {
- if (fsm_getstate(ch->fsm) < CH_XID7_PENDING4) {
- fsm_newstate(ch->fsm, CH_XID7_PENDING4);
- memcpy(skb_put(ch->xid_skb,
- TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
- ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL;
- send = 1;
- }
- } else if (fsm_getstate(ch->fsm) == CH_XID7_PENDING3) {
- fsm_newstate(ch->fsm, CH_XID7_PENDING4);
- ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD;
- memcpy(skb_put(ch->xid_skb, TH_HEADER_LENGTH),
- &thdummy, TH_HEADER_LENGTH);
- send = 1;
- }
- }
- if (send)
- fsm_event(grp->fsm, MPCG_EVENT_DOIO, ch);
- }
- return;
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_rcvd_xid0(fsm_instance *fsm, int event, void *arg)
- {
- struct mpcg_info *mpcginfo = arg;
- struct channel *ch = mpcginfo->ch;
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- CTCM_PR_DEBUG("%s: ch-id:%s xid2:%i xid7:%i xidt_p2:%i \n",
- __func__, ch->id, grp->outstanding_xid2,
- grp->outstanding_xid7, grp->outstanding_xid7_p2);
- if (fsm_getstate(ch->fsm) < CH_XID7_PENDING)
- fsm_newstate(ch->fsm, CH_XID7_PENDING);
- grp->outstanding_xid2--;
- grp->outstanding_xid7++;
- grp->outstanding_xid7_p2++;
- /* must change state before validating xid to */
- /* properly handle interim interrupts received*/
- switch (fsm_getstate(grp->fsm)) {
- case MPCG_STATE_XID2INITW:
- fsm_newstate(grp->fsm, MPCG_STATE_XID2INITX);
- mpc_validate_xid(mpcginfo);
- break;
- case MPCG_STATE_XID0IOWAIT:
- fsm_newstate(grp->fsm, MPCG_STATE_XID0IOWAIX);
- mpc_validate_xid(mpcginfo);
- break;
- case MPCG_STATE_XID2INITX:
- if (grp->outstanding_xid2 == 0) {
- fsm_newstate(grp->fsm, MPCG_STATE_XID7INITW);
- mpc_validate_xid(mpcginfo);
- fsm_event(grp->fsm, MPCG_EVENT_XID2DONE, dev);
- }
- break;
- case MPCG_STATE_XID0IOWAIX:
- if (grp->outstanding_xid2 == 0) {
- fsm_newstate(grp->fsm, MPCG_STATE_XID7INITI);
- mpc_validate_xid(mpcginfo);
- fsm_event(grp->fsm, MPCG_EVENT_XID2DONE, dev);
- }
- break;
- }
- kfree(mpcginfo);
- CTCM_PR_DEBUG("ctcmpc:%s() %s xid2:%i xid7:%i xidt_p2:%i \n",
- __func__, ch->id, grp->outstanding_xid2,
- grp->outstanding_xid7, grp->outstanding_xid7_p2);
- CTCM_PR_DEBUG("ctcmpc:%s() %s grpstate: %s chanstate: %s \n",
- __func__, ch->id,
- fsm_getstate_str(grp->fsm), fsm_getstate_str(ch->fsm));
- return;
- }
- /*
- * MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static void mpc_action_rcvd_xid7(fsm_instance *fsm, int event, void *arg)
- {
- struct mpcg_info *mpcginfo = arg;
- struct channel *ch = mpcginfo->ch;
- struct net_device *dev = ch->netdev;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- CTCM_PR_DEBUG("Enter %s: cp=%i ch=0x%p id=%s\n",
- __func__, smp_processor_id(), ch, ch->id);
- CTCM_PR_DEBUG("%s: outstanding_xid7: %i, outstanding_xid7_p2: %i\n",
- __func__, grp->outstanding_xid7, grp->outstanding_xid7_p2);
- grp->outstanding_xid7--;
- ch->xid_skb->data = ch->xid_skb_data;
- skb_reset_tail_pointer(ch->xid_skb);
- ch->xid_skb->len = 0;
- switch (fsm_getstate(grp->fsm)) {
- case MPCG_STATE_XID7INITI:
- fsm_newstate(grp->fsm, MPCG_STATE_XID7INITZ);
- mpc_validate_xid(mpcginfo);
- break;
- case MPCG_STATE_XID7INITW:
- fsm_newstate(grp->fsm, MPCG_STATE_XID7INITX);
- mpc_validate_xid(mpcginfo);
- break;
- case MPCG_STATE_XID7INITZ:
- case MPCG_STATE_XID7INITX:
- if (grp->outstanding_xid7 == 0) {
- if (grp->outstanding_xid7_p2 > 0) {
- grp->outstanding_xid7 =
- grp->outstanding_xid7_p2;
- grp->outstanding_xid7_p2 = 0;
- } else
- fsm_newstate(grp->fsm, MPCG_STATE_XID7INITF);
- mpc_validate_xid(mpcginfo);
- fsm_event(grp->fsm, MPCG_EVENT_XID7DONE, dev);
- break;
- }
- mpc_validate_xid(mpcginfo);
- break;
- }
- kfree(mpcginfo);
- return;
- }
- /*
- * mpc_action helper of an MPC Group Station FSM action
- * CTCM_PROTO_MPC only
- */
- static int mpc_send_qllc_discontact(struct net_device *dev)
- {
- __u32 new_len = 0;
- struct sk_buff *skb;
- struct qllc *qllcptr;
- struct ctcm_priv *priv = dev->ml_priv;
- struct mpc_group *grp = priv->mpcg;
- CTCM_PR_DEBUG("%s: GROUP STATE: %s\n",
- __func__, mpcg_state_names[grp->saved_state]);
- switch (grp->saved_state) {
- /*
- * establish conn callback function is
- * preferred method to report failure
- */
- case MPCG_STATE_XID0IOWAIT:
- case MPCG_STATE_XID0IOWAIX:
- case MPCG_STATE_XID7INITI:
- case MPCG_STATE_XID7INITZ:
- case MPCG_STATE_XID2INITW:
- case MPCG_STATE_XID2INITX:
- case MPCG_STATE_XID7INITW:
- case MPCG_STATE_XID7INITX:
- if (grp->estconnfunc) {
- grp->estconnfunc(grp->port_num, -1, 0);
- grp->estconnfunc = NULL;
- break;
- }
- case MPCG_STATE_FLOWC:
- case MPCG_STATE_READY:
- grp->send_qllc_disc = 2;
- new_len = sizeof(struct qllc);
- qllcptr = kzalloc(new_len, gfp_type() | GFP_DMA);
- if (qllcptr == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): qllcptr allocation error",
- CTCM_FUNTAIL, dev->name);
- return -ENOMEM;
- }
- qllcptr->qllc_address = 0xcc;
- qllcptr->qllc_commands = 0x03;
- skb = __dev_alloc_skb(new_len, GFP_ATOMIC);
- if (skb == NULL) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): skb allocation error",
- CTCM_FUNTAIL, dev->name);
- priv->stats.rx_dropped++;
- kfree(qllcptr);
- return -ENOMEM;
- }
- memcpy(skb_put(skb, new_len), qllcptr, new_len);
- kfree(qllcptr);
- if (skb_headroom(skb) < 4) {
- CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
- "%s(%s): skb_headroom error",
- CTCM_FUNTAIL, dev->name);
- dev_kfree_skb_any(skb);
- return -ENOMEM;
- }
- *((__u32 *)skb_push(skb, 4)) =
- priv->channel[CTCM_READ]->pdu_seq;
- priv->channel[CTCM_READ]->pdu_seq++;
- CTCM_PR_DBGDATA("ctcmpc: %s ToDCM_pdu_seq= %08x\n",
- __func__, priv->channel[CTCM_READ]->pdu_seq);
- /* receipt of CC03 resets anticipated sequence number on
- receiving side */
- priv->channel[CTCM_READ]->pdu_seq = 0x00;
- skb_reset_mac_header(skb);
- skb->dev = dev;
- skb->protocol = htons(ETH_P_SNAP);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- CTCM_D3_DUMP(skb->data, (sizeof(struct qllc) + 4));
- netif_rx(skb);
- break;
- default:
- break;
- }
- return 0;
- }
- /* --- This is the END my friend --- */
|