Cleanup and improve mode detection. Now, you should get what you actually

want according to the modes set with the ppc(4) flags. Especially, it
should fix some problems with mode detection of parallel chipsets
configured to EPP but which have timing troubles with the drives. In such
a case, the driver should now fall back to slower modes (PS2, NIBBLE).
This commit is contained in:
Nicolas Souchu 2001-01-02 21:29:06 +00:00
parent 63c90c9e57
commit adb50a3799
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=70608
3 changed files with 98 additions and 183 deletions

View File

@ -372,14 +372,34 @@ imm_detect(struct vpoio_data *vpo)
/* disconnect the drive, keep the bus */
imm_disconnect(vpo, NULL, 0);
/* we already have the bus, just connect */
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
vpo->vpo_mode_found = VP0_MODE_UNDEFINED;
error = 1;
/* try to enter EPP mode since vpoio failure put the bus in NIBBLE */
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
}
/* if connection failed try PS/2 then NIBBLE modes */
if (error) {
if (bootverbose)
printf("imm%d: can't connect to the drive\n",
vpo->vpo_unit);
goto error;
if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
}
if (error) {
if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) {
imm_connect(vpo, PPB_DONTWAIT, &error, 0);
if (error)
goto error;
vpo->vpo_mode_found = VP0_MODE_NIBBLE;
} else {
printf("imm%d: NIBBLE mode unavailable!\n", vpo->vpo_unit);
goto error;
}
} else {
vpo->vpo_mode_found = VP0_MODE_PS2;
}
} else {
vpo->vpo_mode_found = VP0_MODE_EPP;
}
/* send SCSI reset signal */
@ -554,7 +574,6 @@ int
imm_attach(struct vpoio_data *vpo)
{
device_t ppbus = device_get_parent(vpo->vpo_dev);
int epp;
/*
* Initialize microsequence code
@ -576,64 +595,25 @@ imm_attach(struct vpoio_data *vpo)
*/
ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT);
/* enter NIBBLE mode to configure submsq */
if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) {
ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
}
/* enter PS2 mode to configure submsq */
if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
/* ppbus automatically restore the last mode entered during detection */
switch (vpo->vpo_mode_found) {
case VP0_MODE_EPP:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr);
printf("imm%d: EPP mode\n", vpo->vpo_unit);
break;
case VP0_MODE_PS2:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
}
epp = ppb_get_epp_protocol(ppbus);
/* enter EPP mode to configure submsq */
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
switch (epp) {
case EPP_1_9:
case EPP_1_7:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr);
break;
default:
panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
epp);
}
}
/* try to enter EPP or PS/2 mode, NIBBLE otherwise */
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
switch (epp) {
case EPP_1_9:
printf("imm%d: EPP 1.9 mode\n", vpo->vpo_unit);
break;
case EPP_1_7:
printf("imm%d: EPP 1.7 mode\n", vpo->vpo_unit);
break;
default:
panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
epp);
}
} else if (ppb_set_mode(ppbus, PPB_PS2) != -1)
printf("imm%d: PS2 mode\n", vpo->vpo_unit);
else if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1)
break;
case VP0_MODE_NIBBLE:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
printf("imm%d: NIBBLE mode\n", vpo->vpo_unit);
else {
printf("imm%d: can't enter NIBBLE, PS2 or EPP mode\n",
vpo->vpo_unit);
ppb_release_bus(ppbus, vpo->vpo_dev);
free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF);
return (ENXIO);
break;
default:
panic("imm: unknown mode %d", vpo->vpo_mode_found);
}
ppb_release_bus(ppbus, vpo->vpo_dev);

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 1998, 1999 Nicolas Souchu
* Copyright (c) 2000 Alcove - Nicolas Souchu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -364,24 +365,38 @@ vpoio_detect(struct vpoio_data *vpo)
return (error);
ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret);
/* Force disconnection */
if (PPB_IN_EPP_MODE(ppbus))
/* Try to enter EPP mode, then connect to the drive in EPP mode */
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
/* call manually the microseq instead of using the appropriate function
* since we already requested the ppbus */
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret);
else
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
}
ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
if (!ret) {
/* If EPP mode switch failed or ZIP connection in EPP mode failed,
* try to connect in NIBBLE mode */
if (!vpoio_in_disk_mode(vpo)) {
/* try spp mode (maybe twice or because previous mode was PS2)
* NIBBLE mode will be restored on next transfers if detection
* succeed
/* The interface must be at least PS/2 or NIBBLE capable.
* There is no way to know if the ZIP will work with
* PS/2 mode since PS/2 and SPP both use the same connect
* sequence. One must supress PS/2 with boot flags if
* PS/2 mode fails (see ppc(4)).
*/
ppb_set_mode(ppbus, PPB_NIBBLE);
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
vpo->vpo_mode_found = VP0_MODE_PS2;
} else {
if (ppb_set_mode(ppbus, PPB_NIBBLE) == -1)
goto error;
ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
if (!ret) {
vpo->vpo_mode_found = VP0_MODE_NIBBLE;
}
/* Can't know if the interface is capable of PS/2 yet */
ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret);
if (!vpoio_in_disk_mode(vpo)) {
vpo->vpo_mode_found = VP0_MODE_UNDEFINED;
if (bootverbose)
printf("vpo%d: can't connect to the drive\n",
vpo->vpo_unit);
@ -391,6 +406,8 @@ vpoio_detect(struct vpoio_data *vpo)
&ret);
goto error;
}
} else {
vpo->vpo_mode_found = VP0_MODE_EPP;
}
/* send SCSI reset signal */
@ -400,9 +417,7 @@ vpoio_detect(struct vpoio_data *vpo)
/* ensure we are disconnected or daisy chained peripheral
* may cause serious problem to the disk */
ppb_MS_microseq(ppbus, vpo->vpo_dev, in_disk_mode, &ret);
if (ret) {
if (vpoio_in_disk_mode(vpo)) {
if (bootverbose)
printf("vpo%d: can't disconnect from the drive\n",
vpo->vpo_unit);
@ -429,28 +444,6 @@ vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size)
ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_PUT, (union ppb_insarg)buffer,
(union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
#if 0
/* XXX EPP 1.9 not implemented with microsequences */
else {
ppb_reset_epp_timeout(ppbus);
ppb_wctr(ppbus, H_AUTO | H_SELIN | H_INIT | H_STROBE);
if (((long) buffer | size) & 0x03)
ppb_outsb_epp(ppbus,
buffer, size);
else
ppb_outsl_epp(ppbus,
buffer, size/4);
if ((ppb_rstr(ppbus) & TIMEOUT)) {
error = VP0_EPPDATA_TIMEOUT;
goto error;
}
ppb_wctr(ppbus, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
}
#endif
ppb_ecp_sync(ppbus);
return (error);
@ -468,30 +461,6 @@ vpoio_instr(struct vpoio_data *vpo, char *buffer, int size)
ppb_MS_exec(ppbus, vpo->vpo_dev, MS_OP_GET, (union ppb_insarg)buffer,
(union ppb_insarg)size, (union ppb_insarg)MS_UNKNOWN, &error);
#if 0
/* XXX EPP 1.9 not implemented with microsequences */
else {
ppb_reset_epp_timeout(ppbus);
ppb_wctr(ppbus, PCD |
H_AUTO | H_SELIN | H_INIT | H_STROBE);
if (((long) buffer | size) & 0x03)
ppb_insb_epp(ppbus,
buffer, size);
else
ppb_insl_epp(ppbus,
buffer, size/4);
if ((ppb_rstr(ppbus) & TIMEOUT)) {
error = VP0_EPPDATA_TIMEOUT;
goto error;
}
ppb_wctr(ppbus, PCD |
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
}
#endif
ppb_ecp_sync(ppbus);
return (error);
@ -614,7 +583,7 @@ int
vpoio_attach(struct vpoio_data *vpo)
{
device_t ppbus = device_get_parent(vpo->vpo_dev);
int epp;
int error = 0;
vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(
sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);
@ -631,75 +600,34 @@ vpoio_attach(struct vpoio_data *vpo)
/*
* Initialize mode dependent in/out microsequences
*/
ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT);
/* enter NIBBLE mode to configure submsq */
if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1) {
ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
}
/* enter PS2 mode to configure submsq */
if (ppb_set_mode(ppbus, PPB_PS2) != -1) {
if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_WAIT)))
goto error;
/* ppbus sets automatically the last mode entered during detection */
switch (vpo->vpo_mode_found) {
case VP0_MODE_EPP:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr_body);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr_body);
printf("vpo%d: EPP mode\n", vpo->vpo_unit);
break;
case VP0_MODE_PS2:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, ps2_inbyte_submicroseq);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
}
epp = ppb_get_epp_protocol(ppbus);
/* enter EPP mode to configure submsq */
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
switch (epp) {
case EPP_1_9:
/* XXX EPP 1.9 support should be improved */
case EPP_1_7:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, epp17_instr_body);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, epp17_outstr_body);
break;
default:
panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
epp);
}
}
/* try to enter EPP or PS/2 mode, NIBBLE otherwise */
if (ppb_set_mode(ppbus, PPB_EPP) != -1) {
switch (epp) {
case EPP_1_9:
printf("vpo%d: EPP 1.9 mode\n", vpo->vpo_unit);
break;
case EPP_1_7:
printf("vpo%d: EPP 1.7 mode\n", vpo->vpo_unit);
break;
default:
panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
epp);
}
} else if (ppb_set_mode(ppbus, PPB_PS2) != -1)
printf("vpo%d: PS2 mode\n", vpo->vpo_unit);
else if (ppb_set_mode(ppbus, PPB_NIBBLE) != -1)
break;
case VP0_MODE_NIBBLE:
ppb_MS_GET_init(ppbus, vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
ppb_MS_PUT_init(ppbus, vpo->vpo_dev, spp_outbyte_submicroseq);
printf("vpo%d: NIBBLE mode\n", vpo->vpo_unit);
else {
printf("vpo%d: can't enter NIBBLE, PS2 or EPP mode\n",
vpo->vpo_unit);
ppb_release_bus(ppbus, vpo->vpo_dev);
free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF);
return (ENXIO);
break;
default:
panic("vpo: unknown mode %d", vpo->vpo_mode_found);
}
ppb_release_bus(ppbus, vpo->vpo_dev);
return (0);
error:
return (error);
}
/*

View File

@ -59,8 +59,15 @@ struct vpo_nibble {
char l; /* less significant nibble */
};
/* Mode found during initialisation */
#define VP0_MODE_UNDEFINED 0x0
#define VP0_MODE_NIBBLE 0x1
#define VP0_MODE_PS2 0x2
#define VP0_MODE_EPP 0x3
struct vpoio_data {
unsigned short int vpo_unit;
int vpo_mode_found; /* Mode found during init */
struct vpo_nibble vpo_nibble;