-
-/***********************************************************************
- * Functions: dc390_inquiry(), dc390_inquiry_done()
- *
- * Purpose: When changing speed etc., we have to issue an INQUIRY
- * command to make sure, we agree upon the nego parameters
- * with the device
- ***********************************************************************/
-
-static void dc390_inquiry_done (Scsi_Cmnd* cmd)
-{
- printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
- cmd->device->id, cmd->device->lun, cmd->result);
- if (cmd->result)
- {
- PACB pACB = (PACB)cmd->device->host->hostdata;
- PDCB pDCB = dc390_findDCB (pACB, cmd->device->id, cmd->device->lun);
- printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
- if (pDCB)
- {
- pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ );
- dc390_updateDCB (pACB, pDCB);
- }
- }
- kfree (cmd);
-}
-
-void dc390_inquiry (PACB pACB, PDCB pDCB)
-{
- char* buffer;
- Scsi_Cmnd* cmd;
- cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
- if (!cmd) { printk ("DC390: kmalloc failed in inquiry!\n"); return; }
- buffer = (char*)cmd + sizeof(Scsi_Cmnd);
-
- memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
- cmd->cmnd[0] = INQUIRY;
- cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
- cmd->cmnd[4] = 0xff;
-
- cmd->cmd_len = 6; cmd->old_cmd_len = 6;
-/* TODO FIXME */
-/* cmd->host = pACB->pScsiHost; */
- cmd->device->id = pDCB->TargetID;
- cmd->device->lun = pDCB->TargetLUN;
- cmd->serial_number = 1;
- cmd->pid = 390;
- cmd->bufflen = 128;
- cmd->buffer = buffer;
- cmd->request_bufflen = 128;
- cmd->request_buffer = &buffer[128];
- cmd->done = dc390_inquiry_done;
- cmd->scsi_done = dc390_inquiry_done;
- cmd->timeout_per_command = HZ;
-
- cmd->request->rq_status = RQ_SCSI_BUSY;
-
- pDCB->SyncMode &= ~SYNC_NEGO_DONE;
- printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
- pDCB->TargetID, pDCB->TargetLUN);
- DC390_queue_command (cmd, dc390_inquiry_done);
-}
-
-/***********************************************************************
- * Functions: dc390_sendstart(), dc390_sendstart_done()
- *
- * Purpose: When changing speed etc., we have to issue an INQUIRY
- * command to make sure, we agree upon the nego parameters
- * with the device
- ***********************************************************************/
-
-static void dc390_sendstart_done (Scsi_Cmnd* cmd)
-{
- printk (KERN_INFO "DC390: SENDSTART (ID %02x LUN %02x) returned %08x\n",
- cmd->device->id, cmd->device->lun, cmd->result);
- kfree (cmd);
-}
-
-void dc390_sendstart (PACB pACB, PDCB pDCB)
-{
- char* buffer;
- Scsi_Cmnd* cmd;
- cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
- if (!cmd) { printk ("DC390: kmalloc failed in sendstart!\n"); return; }
- buffer = (char*)cmd + sizeof(Scsi_Cmnd);
-
- memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
- cmd->cmnd[0] = 0x1b; /* START_STOP_UNIT */
- cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
- cmd->cmnd[4] = 0x01; /* START */
-
- cmd->cmd_len = 6; cmd->old_cmd_len = 6;
-/* TODO FIXME */
-/* cmd->host = pACB->pScsiHost; */
- cmd->device->id = pDCB->TargetID;
- cmd->device->lun = pDCB->TargetLUN;
- cmd->serial_number = 1;
- cmd->pid = 310;
- cmd->bufflen = 128;
- cmd->buffer = buffer;
- cmd->request_bufflen = 128;
- cmd->request_buffer = &buffer[128];
- cmd->done = dc390_sendstart_done;
- cmd->scsi_done = dc390_sendstart_done;
- cmd->timeout_per_command = 5*HZ;
-
- cmd->request->rq_status = RQ_SCSI_BUSY;
-
- pDCB->SyncMode &= ~SYNC_NEGO_DONE;
- printk (KERN_INFO "DC390: Queue SEND_START command to dev ID %02x LUN %02x\n",
- pDCB->TargetID, pDCB->TargetLUN);
- DC390_queue_command (cmd, dc390_sendstart_done);
-}
-
-/********************************************************************
- * Function: dc390_set_info()
- *
- * Purpose: Change adapter config
- *
- * Strings are parsed similar to the output of tmscsim_proc_info ()
- * '-' means no change
- *******************************************************************/
-
-static int dc390_scanf (char** buffer, char** pos, char** p0, int* var)
-{
- *p0 = *pos;
- *var = simple_strtoul (*p0, pos, 10);
- if (*p0 == *pos) return -1;
- *pos = strsep (buffer, " \t\n:=,;.");
- return 0;
-}
-
-#define SCANF(buffer, pos, p0, var, min, max) \
-if (dc390_scanf (&buffer, &pos, &p0, &var)) goto einv; \
-else if (var<min || var>max) goto einv2
-
-static int dc390_yesno (char** buffer, char** pos, char* var, char bmask)
-{
- switch (**pos)
- {
- case 'Y': *var |= bmask; break;
- case 'N': *var &= ~bmask; break;
- case '-': break;
- default: return -1;
- }
- *pos = strsep (buffer, " \t\n:=,;");
- return 0;
-}
-
-#define YESNO(buffer, pos, var, bmask) \
- if (dc390_yesno (&buffer, &pos, &var, bmask)) goto einv; \
- else dc390_updateDCB (pACB, pDCB); \
- if (!pos) goto ok
-
-static int dc390_search (char** buffer, char** pos, char** p0, char* var, char* txt, int max, int scale, char* ign)
-{
- int dum;
- if (! memcmp (*pos, txt, strlen(txt)))
- {
- *p0 = strsep (buffer, " \t\n:=,;");
- if (!*p0) return -1;
- dum = simple_strtoul (*p0, pos, 10);
- if (*p0 == *pos) return -1;
- if (dum >= 0 && dum <= max)
- { *var = (dum * 100) / scale; }
- else return -2;
- *pos = strsep (buffer, " \t\n:=,;");
- if (*ign && *pos && strlen(*pos) >= strlen(ign) &&
- !(memcmp (*pos, ign, strlen(ign))))
- *pos = strsep (buffer, " \t\n:=,;");
-
- }
- return 0;
-}
-
-#define SEARCH(buffer, pos, p0, var, txt, max) \
-if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
-else if (!p1) goto ok2
-
-#define SEARCH2(buffer, pos, p0, var, txt, max, scale) \
-if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \
-else if (!p1) goto ok2
-
-#define SEARCH3(buffer, pos, p0, var, txt, max, scale, ign) \
-if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, ign)) goto einv2; \
-else if (!p1) goto ok2
-
-
-#ifdef DC390_PARSEDEBUG
-static char _prstr[256];
-char* prstr (char* p, char* e)
-{
- char* c = _prstr;
- while (p < e)
- if (*p == 0) { *c++ = ':'; p++; }
- else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
- else *c++ = *p++;
- *c = 0;
- return _prstr;
-}
-#endif
-
-int dc390_set_info (char *buffer, int length, PACB pACB)
-{
- char *pos = buffer, *p0 = buffer;
- char needs_inquiry = 0;
- int dum = 0;
- char dev;
- PDCB pDCB = pACB->pLinkDCB;
- DC390_IFLAGS;
- DC390_AFLAGS;
- pos[length] = 0;
-
- DC390_LOCK_IO(pACB->pScsiHost);
- DC390_LOCK_ACB;
- /* UPPERCASE */
- /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
- while (*pos)
- { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; }
-
- /* Remove WS */
- pos = strsep (&buffer, " \t:\n=,;");
- if (!*pos) goto ok;
-
- next:
- if (!memcmp (pos, "RESET", 5)) goto reset;
- else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
- else if (!memcmp (pos, "REMOVE", 6)) goto remove;
- else if (!memcmp (pos, "ADD", 3)) goto add;
- else if (!memcmp (pos, "START", 5)) goto start;
- else if (!memcmp (pos, "DUMP", 4)) goto dump;
-
- if (isdigit (*pos))
- {
- /* Device config line */
- int dev, id, lun; char* pdec;
- char olddevmode;
-
- SCANF (buffer, pos, p0, dev, 0, pACB->DCBCnt-1);
- if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
- if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
- if (!*pos) goto einv;
-
- PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length])));
- pDCB = pACB->pLinkDCB;
- for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
- /* Sanity Check */
- if (pDCB->TargetID != id || pDCB->TargetLUN != lun)
- {
- printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
- dev, id, lun);
- goto einv2;
- }
-
- if (pDCB->pWaitingSRB || pDCB->pGoingSRB)
- {
- printk ("DC390: Cannot change dev (%i-%i) cfg: Pending requests\n",
- pDCB->TargetID, pDCB->TargetLUN);
- goto einv;
- }
-
- olddevmode = pDCB->DevMode;
- YESNO (buffer, pos, pDCB->DevMode, PARITY_CHK_);
- needs_inquiry++;
- YESNO (buffer, pos, pDCB->DevMode, SYNC_NEGO_);
- if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
- needs_inquiry++;
- YESNO (buffer, pos, pDCB->DevMode, EN_DISCONNECT_);
- if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
- YESNO (buffer, pos, pDCB->DevMode, SEND_START_);
- needs_inquiry++;
- YESNO (buffer, pos, pDCB->DevMode, TAG_QUEUEING_);
- if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
-
- dc390_updateDCB (pACB, pDCB);
- if (!*pos) goto ok;
-
- olddevmode = pDCB->NegoPeriod;
- /* Look for decimal point (Speed) */
- pdec = pos;
- while (pdec++ < &buffer[length]) if (*pdec == '.') break;
- /* NegoPeriod */
- if (*pos != '-')
- {
- SCANF (buffer, pos, p0, dum, 72, 800);
- pDCB->NegoPeriod = dum >> 2;
- if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
- if (!pos) goto ok;
- if (memcmp (pos, "NS", 2) == 0) pos = strsep (&pos, " \t\n:=,;.");
- }
- else pos = strsep (&pos, " \t\n:=,;.");
- if (!*pos) goto ok;
-
- /* Sync Speed in MHz */
- if (*pos != '-')
- {
- SCANF (buffer, pos, p0, dum, 1, 13);
- pDCB->NegoPeriod = (1000/dum) >> 2;
- if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
- if (!*pos) goto ok;
- /* decimal */
- if (pos-1 == pdec)
- {
- int dumold = dum;
- dum = simple_strtoul (pos, &p0, 10) * 10;
- for (; p0-pos > 1; p0--) dum /= 10;
- pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
- if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
- pos = strsep (&pos, " \t\n:=,;");
- if (!*pos) goto ok;
- }
- if (*pos == 'M') pos = strsep (&pos, " \t\n:=,;");
- if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
- }
- else pos = strsep (&pos, " \t\n:=,;");
- /* dc390_updateDCB (pACB, pDCB); */
- if (!*pos) goto ok;
-
- olddevmode = pDCB->SyncOffset;
- /* SyncOffs */
- if (*pos != '-')
- {
- SCANF (buffer, pos, p0, dum, 0, 0x0f);
- pDCB->SyncOffset = dum;
- if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
- }
- else pos = strsep (&pos, " \t\n:=,;");
- if (!*pos) goto ok;
- dc390_updateDCB (pACB, pDCB);
-
- //olddevmode = pDCB->MaxCommand;
- /* MaxCommand (Tags) */
- if (*pos != '-')
- {
- SCANF (buffer, pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
- if (pDCB->SyncMode & EN_TAG_QUEUEING)
- pDCB->MaxCommand = dum;
- else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n");
- }
- else pos = strsep (&pos, " \t\n:=,;");
-
- }
- else
- {
- char* p1 = pos; UCHAR dum, newadaptid;
- PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length])));
- dum = GLITCH_TO_NS (pACB->glitch_cfg);
- /* Adapter setting */
- SEARCH (buffer, pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
- SEARCH (buffer, pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
- SEARCH (buffer, pos, p0, newadaptid, "ADAPTERID", 7);
- SEARCH (buffer, pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
- SEARCH (buffer, pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
- SEARCH3 (buffer, pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
- SEARCH3 (buffer, pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
- SEARCH3 (buffer, pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
- ok2:
- pACB->glitch_cfg = NS_TO_GLITCH (dum);
- if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
- DC390_write8 (Scsi_TimeOut, pACB->sel_timeout);
- if (newadaptid != pACB->pScsiHost->this_id)
- {
- pACB->pScsiHost->this_id = newadaptid;
- dc390_ResetDevParam (pACB);
- }
- //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
- //pACB->TagMaxNum &= (1 << --dum);
- dc390_updateDCBs (pACB);
- // All devs should be INQUIRED now
- if (pos == p1) goto einv;
- }
- if (*pos) goto next;
-
- ok:
- DC390_UNLOCK_ACB;
- if (needs_inquiry)
- { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); }
- DC390_UNLOCK_IO(pACB->pScsiHost);
- return (length);
-
- einv2:
- pos = p0;
- einv:
- DC390_UNLOCK_ACB;
- DC390_UNLOCK_IO(pACB->pScsiHost);
- printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
- return (-EINVAL);
-
- reset:
- {
- Scsi_Cmnd cmd;
- /* TODO FIXME */
- /* cmd.host = pACB->pScsiHost; */
- printk (KERN_WARNING "DC390: Driver reset requested!\n");
- DC390_UNLOCK_ACB;
- DC390_reset (&cmd);
- DC390_UNLOCK_IO(pACB->pScsiHost);
- }
- return (length);
-
- dump:
- {
- dc390_dumpinfo (pACB, 0, 0);
- DC390_UNLOCK_ACB;
- DC390_UNLOCK_IO(pACB->pScsiHost);
- }
- return (length);
-
- inquiry:
- {
- pos = strsep (&pos, " \t\n.:;="); if (!*pos) goto einv;
- dev = simple_strtoul (pos, &p0, 10);
- if (dev >= pACB->DCBCnt) goto einv_dev;
- for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
- printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
- dev, pDCB->TargetID, pDCB->TargetLUN);
- DC390_UNLOCK_ACB;
- dc390_inquiry (pACB, pDCB);
- DC390_UNLOCK_IO(pACB->pScsiHost);
- }
- return (length);
-
- remove:
- {
- pos = strsep (&pos, " \t\n.:;="); if (!*pos) goto einv;
- dev = simple_strtoul (pos, &p0, 10);
- if (dev >= pACB->DCBCnt) goto einv_dev;
- for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
- printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
- dev, pDCB->TargetID, pDCB->TargetLUN);
- /* TO DO: We should make sure no pending commands are left */
- dc390_remove_dev (pACB, pDCB);
- DC390_UNLOCK_ACB;
- DC390_UNLOCK_IO(pACB->pScsiHost);
- }
- return (length);
-
- add:
- {
- int id, lun;
- pos = strsep (&pos, " \t\n.:;=");
- if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
- if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
- pDCB = dc390_findDCB (pACB, id, lun);
- if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; }
- dc390_initDCB (pACB, &pDCB, id, lun);
- DC390_UNLOCK_ACB;
- dc390_inquiry (pACB, pDCB);
- DC390_UNLOCK_IO(pACB->pScsiHost);
- }
- return (length);
-
- start:
- {
- int id, lun;
- pos = strsep (&pos, " \t\n.:;=");
- if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
- if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
- pDCB = dc390_findDCB (pACB, id, lun);
- if (pDCB) printk ("DC390: SendStart: Device already existing ...\n");
- else dc390_initDCB (pACB, &pDCB, id, lun);
- DC390_UNLOCK_ACB;
- dc390_sendstart (pACB, pDCB);
- dc390_inquiry (pACB, pDCB);
- DC390_UNLOCK_IO(pACB->pScsiHost);
- }
- return (length);
-
- einv_dev:
- printk (KERN_WARNING "DC390: Ignore cmnd to invalid Dev(Idx) %i. Valid range: 0 - %i.\n",
- dev, pACB->DCBCnt - 1);
- DC390_UNLOCK_ACB;
- DC390_UNLOCK_IO(pACB->pScsiHost);
- return (-EINVAL);
-}
-
-#undef SEARCH
-#undef YESNO
-#undef SCANF
-