/* * comprueba si la secuencia identificadores de elemento * concuerda con la regla de tipo 'child' dada por el * puntero. * * la secuencia 'elements' es un array de identificadores ordenada * el número de elementos del array lo indica 'num' * el puntero a la regla es 'rule_ptr' * * DEVUELVE: 1 si lo es o 0 si no lo es (-1 si lo podría ser con * más elementos) * */ int dtd_is_child_valid(int rule_ptr, int elements[], int num) { int rule; int valid; DEBUG("dtd_is_child_valid()"); rule= rule_ptr; valid=is_child_valid(&rule, elements, num); EPRINTF2(" código retornado: %d [regla %d]\n",valid,rule); if (valid==num) return 1; else if (valid==-2) return -1; /* no válido, pero por falta de elm */ /* no válido */ else return 0; }
/* * * función recursiva en la que se basa el funcionamiento de * dtd_is_child_valid() * * devuelve: <0: no es válido * num: es válido con 'num' elementos coincidentes * */ static int is_child_valid(int *rule_ptr, int elements[], int num) { unsigned char data; int is_choice; int repeat; int rule; int elm; int valid = -1; int elm_matched; int error_code; int coincide_choice; #ifdef CHILD_DEBUG char str[1024]; int len_buff= 0; int i; #endif DEBUG("is_child_valid()"); #ifdef CHILD_DEBUG EPRINTF2(" rule: %d; num: %d;\n", *rule_ptr, num); EPRINTF1(" %s\n", contentspecToString(&elm_buffer[*rule_ptr], str, CONTTYPE_CHILDREN, &len_buff)); EPRINTF(" :: "); for (i=0; i<num; i++) EPRINTF1("%s ", elm_list[elements[i]].name); EPRINTF("\n"); #endif coincide_choice= 0; error_code= -1; rule= *rule_ptr; data= elm_buffer[rule]; if (!CSPEC_ISPAR(data) || (!(data & CSPEC_PAR_O))) EXIT("dtd_is_child_valid ¡la regla no empieza con '('!"); is_choice= CSPEC_ISCHOICE(data); repeat= CSPEC_NUM(data); #ifdef CHILD_DEBUG if (is_choice) EPRINTF(" | "); else EPRINTF(" , "); switch (repeat) { case CSPEC_AST: EPRINTF("*\n"); break; case CSPEC_MAS: EPRINTF("+\n"); break; case CSPEC_INT: EPRINTF("?\n"); break; default: EPRINTF("1\n"); break; } #endif elm= 0; elm_matched= 0; data= elm_buffer[++rule]; for ( ; ; data= elm_buffer[++rule]) { /* mira si es válido el elemento actual */ if (CSPEC_ISELM(data)) { /* es un elemento suelto */ if ((elm<num) && elements[elm]==CSPEC_ELM(data)) valid= 1; else if (elm>=num) valid=-2; /* faltan elementos */ else valid= -1; #ifdef CHILD_DEBUG EPRINTF3(" . [%d:%d] %s\n",rule,valid,elm_list[CSPEC_ELM(data)].name); #endif } else if (data & CSPEC_PAR_O) { /* es una regla compuesta: comienza con '(' */ #ifdef CHILD_DEBUG int rule0= rule; EPRINTF1(" >> [%d]\n",rule); #endif valid= is_child_valid(&rule, elements+elm, num-elm); #ifdef CHILD_DEBUG EPRINTF3(" << [%d:%d] %s\n",rule,valid, contentspecToString(&elm_buffer[rule0], str, CONTTYPE_CHILDREN, &len_buff)); EPRINTF1(" -> %s\n", contentspecToString(&elm_buffer[rule+1], str, CONTTYPE_CHILDREN, &len_buff)); #endif } else if (data & CSPEC_PAR_C) { /* fin de esta regla */ #ifdef CHILD_DEBUG EPRINTF2(" )) coincide_choice:%d; elm_matched:%d\n", coincide_choice, elm_matched); #endif if (is_choice) { /* error si no hubo coincidencias en iteraciones anteriores * y el tipo no permite 0 coincidencias */ *rule_ptr= rule; if ((coincide_choice)||(elm_matched>0) ||(repeat==CSPEC_INT)||(repeat==CSPEC_AST)) return elm_matched; else return error_code; } else { /* si no es choice, se cumple */ elm_matched= elm; /* retorna si sólo permite una coincidenecia */ if ((repeat==CSPEC_INT)||(repeat==0)) { *rule_ptr= rule; return elm_matched; } else { /* vuelve a verificar */ rule= *rule_ptr; #ifdef CHILD_DEBUG EPRINTF(" --R--\n"); #endif continue; } } } else EXIT("is_child_valid ¡regla incorrecta!"); /* comprueba el resultado de este elemento */ if (valid>=0) { #ifdef CHILD_DEBUG EPRINTF1(" --V-- %d\n", valid); #endif /* OK, se mira el siguiente elemento (si no es CHOICE) o se finaliza */ elm+= valid; /* si es choice, busca el fin y retorna */ if (is_choice) { elm_matched= elm; coincide_choice= 1; /* si no se emparejó ninguno, * aunque sea válido, se continúa con el siguiente */ if (elm_matched) { /* si es '*' o '+', o continúa el bucle */ if ((!repeat)||(repeat==CSPEC_INT)) { rule= search_par_close(rule+1); *rule_ptr= rule; return elm; } else rule= *rule_ptr; } } /* no es choice, * o es choice válido sin emparejar ningún elemento * ==> se mira si cumple el siguiente elemento */ } else { /* no válido */ /* si no es choice retorna con error */ #ifdef CHILD_DEBUG EPRINTF1(" --NV-- %d\n", valid); #endif if (!is_choice) { rule= search_par_close(rule+1); *rule_ptr= rule; /* error si no hubo coincidencias en iteraciones anteriores * y el tipo no permite 0 coincidencias */ if ((elm_matched>0)||(repeat==CSPEC_INT)||(repeat==CSPEC_AST)) return elm_matched; /* no hay error */ else return valid; /* hay error */ } /* es choice, se sigue probando */ if (valid==-2) error_code= -2; } } /* for */ }
/* * fas_call_pkt_comp does sanity checking to ensure that we don't * call completion twice on the same packet or a packet that has been freed. * if there is a completion function specified, the packet is queued * up and it is left to the fas_callback thread to empty the queue at * a lower priority; note that there is one callback queue per fas * * we use a separate thread for calling back into the target driver * this thread unqueues packets from the callback queue */ void fas_call_pkt_comp(register struct fas *fas, register struct fas_cmd *sp) { TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_START, "fas_call_pkt_comp_start"); ASSERT(sp != 0); ASSERT((sp->cmd_flags & CFLAG_COMPLETED) == 0); ASSERT((sp->cmd_flags & CFLAG_FREE) == 0); ASSERT(sp->cmd_flags & CFLAG_FINISHED); ASSERT(fas->f_ncmds >= fas->f_ndisc); ASSERT((sp->cmd_flags & CFLAG_CMDDISC) == 0); ASSERT(sp != fas->f_current_sp); ASSERT(sp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]); sp->cmd_flags &= ~CFLAG_IN_TRANSPORT; sp->cmd_flags |= CFLAG_COMPLETED; sp->cmd_qfull_retries = 0; /* * if this was an auto request sense, complete immediately to free * the arq pkt */ if (sp->cmd_pkt->pkt_comp && !(sp->cmd_flags & CFLAG_CMDARQ)) { if (sp->cmd_pkt->pkt_reason != CMD_CMPLT) { IPRINTF6("completion for %d.%d, sp=0x%p, " "reason=%s, stats=%x, state=%x\n", Tgt(sp), Lun(sp), (void *)sp, scsi_rname(sp->cmd_pkt->pkt_reason), sp->cmd_pkt->pkt_statistics, sp->cmd_pkt->pkt_state); } else { EPRINTF2("completion queued for %d.%dn", Tgt(sp), Lun(sp)); } /* * append the packet or start a new queue */ mutex_enter(&fas->f_c_mutex); if (fas->f_c_qf) { /* * add to tail */ register struct fas_cmd *dp = fas->f_c_qb; ASSERT(dp != NULL); fas->f_c_qb = sp; sp->cmd_forw = NULL; dp->cmd_forw = sp; } else { /* * start new queue */ fas->f_c_qf = fas->f_c_qb = sp; sp->cmd_forw = NULL; } mutex_exit(&fas->f_c_mutex); } else if ((sp->cmd_flags & CFLAG_CMDARQ) && sp->cmd_pkt->pkt_comp) { /* * pkt_comp may be NULL when we are aborting/resetting but then * the callback will be redone later */ fas_complete_arq_pkt(sp->cmd_pkt); } else { EPRINTF2("No completion routine for 0x%p reason %x\n", (void *)sp, sp->cmd_pkt->pkt_reason); } TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_END, "fas_call_pkt_comp_end"); }