NetBSD/sys/dev/ieee1394/sbp2.c

292 lines
8.9 KiB
C

/* $NetBSD: sbp2.c,v 1.1 2002/02/27 05:12:11 jmc Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by James Chacon.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
static int sbp2_print_data(struct configrom_data *);
static int sbp2_print_dir(u_int8_t);
static void sbp2_init(struct fwnode_softc *, struct fwnode_device_cap *);
static void sbp2_login(struct ieee1394_abuf *, int);
static void sbp2_login_resp(struct ieee1394_abuf *, int);
#ifdef SBP2_DEBUG
#define DPRINTF(x) if (sbp2debug) printf x
#define DPRINTFN(n,x) if (sbp2debug>(n)) printf x
int sbp2debug = 1;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#endif
/* XXX: All the sbp2 routines are a complete hack simply to probe a device for
the moment to make sure all the other code is good. This should all be gutted
out to it's own file and properly abstracted.
*/
static int
sbp2_print_data(struct configrom_data *data)
{
switch (data->key_value) {
case SBP2_KEYVALUE_Command_Set:
printf("SBP2 Command Set: ");
if (data->val == 0x104d8)
printf("SCSI 2\n");
else
printf("0x%08x\n", data->val);
break;
case SBP2_KEYVALUE_Unit_Characteristics:
printf("SBP2 Unit Characteristics: 0x%08x\n", data->val);
break;
case SBP2_KEYVALUE_Command_Set_Revision:
printf("SBP2 Command Set Revision: 0x%08x\n", data->val);
break;
case SBP2_KEYVALUE_Command_Set_Spec_Id:
printf("SBP2 Command Set Spec Id: 0x%08x\n", data->val);
break;
case SBP2_KEYVALUE_Firmware_Revision:
printf("SBP2 Firmware Revision: 0x%08x\n", data->val);
break;
case SBP2_KEYVALUE_Reconnect_Timeout:
printf("SBP2 Reconnect Timeout: 0x%08x\n", data->val);
break;
case SBP2_KEYVALUE_Unit_Unique_Id:
printf("SBP2 Unit Unique Id: 0x%08x\n", data->val);
break;
case P1212_KEYVALUE_Unit_Dependent_Info:
if (data->key_type == P1212_KEYTYPE_Immediate)
printf("SBP2 Logical Unit Number: 0x%08x\n", data->val);
else if (data->key_type == P1212_KEYTYPE_Offset)
printf("SBP2 Management Agent: 0x%08x\n", data->val);
break;
default:
return 0;
}
return 1;
}
static int
sbp2_print_dir(u_int8_t dir_type)
{
switch(dir_type) {
case SBP2_KEYVALUE_Logical_Unit_Directory:
printf("Logical Unit ");
break;
default:
return 0;
}
return 1;
}
static void
sbp2_init(struct fwnode_softc *sc, struct fwnode_device_cap *devcap)
{
struct ieee1394_abuf *ab, *ab2;
u_int32_t loc = ((u_int32_t *)devcap->dev_data)[0];
devcap->dev_valid = 0;
ab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK);
memset(ab, 0, sizeof(struct ieee1394_abuf));
ab->ab_data = malloc(8, M_1394DATA, M_WAITOK);
memset(ab->ab_data, 0, 8);
ab2 = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK);
memset(ab2, 0, sizeof(struct ieee1394_abuf));
loc *= 4;
ab->ab_length = 8;
ab->ab_req = (struct ieee1394_softc *)sc;
ab->ab_retlen = 0;
ab->ab_cb = NULL;
ab->ab_cbarg = NULL;
ab->ab_csr = CSR_BASE + loc;
ab->ab_data[0] = htonl((u_int32_t)(SBP2_LOGIN_ORB >> 32));
ab->ab_data[1] = (u_int32_t)(SBP2_LOGIN_ORB & 0xffffffff);
ab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK;
ab2->ab_length = 32;
ab2->ab_tcode = IEEE1394_TCODE_READ_REQ_BLOCK;
ab2->ab_retlen = 0;
ab2->ab_data = NULL;
ab2->ab_csr = SBP2_LOGIN_ORB;
ab2->ab_cb = sbp2_login;
ab2->ab_cbarg = devcap;
ab2->ab_req = (struct ieee1394_softc *)sc;
sc->sc1394_inreg(ab2, FALSE);
sc->sc1394_write(ab);
return;
}
static void
sbp2_login(struct ieee1394_abuf *ab, int rcode)
{
struct fwnode_softc *sc = (struct fwnode_softc *)ab->ab_req;
/* struct fwnode_device_cap *devcap = ab->ab_cbarg;*/
struct ieee1394_abuf *statab, *respab;
/* Got a read so allocate the buffer and write out the response. */
if (rcode) {
#ifdef FW_DEBUG
printf ("sbp2_login: Bad return code: %d\n", rcode);
#endif
if (ab->ab_data)
free (ab->ab_data, M_1394DATA);
free(ab, M_1394DATA);
}
sc->sc1394_unreg(ab, FALSE);
ab->ab_data = malloc(32, M_1394DATA, M_WAITOK);
respab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK);
statab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK);
memset(respab, 0, sizeof(struct ieee1394_abuf));
memset(statab, 0, sizeof(struct ieee1394_abuf));
statab->ab_length = 32;
statab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK;
statab->ab_retlen = 0;
statab->ab_data = NULL;
statab->ab_csr = SBP2_LOGIN_STATUS;
statab->ab_cb = sbp2_login_resp;
statab->ab_cbarg = ab->ab_cbarg;
statab->ab_req = ab->ab_req;
sc->sc1394_inreg(statab, TRUE);
respab->ab_length = 16;
respab->ab_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK;
respab->ab_retlen = 0;
respab->ab_data = NULL;
respab->ab_csr = SBP2_LOGIN_RESP;
respab->ab_cb = sbp2_login_resp;
respab->ab_cbarg = ab->ab_cbarg;
respab->ab_req = ab->ab_req;
sc->sc1394_inreg(respab, TRUE);
memset(ab->ab_data, 0, 32);
/* Fill in a login packet. First 2 quads are 0 for password. */
/* Addr for response. */
ab->ab_data[2] = htonl(SBP2_LOGIN_RESP >> 32);
ab->ab_data[3] = htonl(SBP2_LOGIN_RESP & 0xffffffff);
/* Set notify and exclusive use bits. Login to lun 0 (XXX) */
ab->ab_data[4] = htonl(0x90000000);
/* Password length (0) and login response length (16) */
ab->ab_data[5] = htonl(0x00000010);
/* Addr for status packet. */
ab->ab_data[6] = htonl(SBP2_LOGIN_STATUS >> 32);
ab->ab_data[7] = htonl(SBP2_LOGIN_STATUS & 0xffffffff);
ab->ab_retlen = 0;
ab->ab_cb = NULL;
ab->ab_cbarg = NULL;
ab->ab_tcode = IEEE1394_TCODE_READ_RESP_BLOCK;
ab->ab_length = 32;
sc->sc1394_write(ab);
}
static void
sbp2_login_resp(struct ieee1394_abuf *ab, int rcode)
{
struct fwnode_softc *sc = (struct fwnode_softc *)ab->ab_req;
struct fwnode_device_cap *devcap = ab->ab_cbarg;
u_int64_t csr;
int resp, src, status, len, dead;
#ifdef FW_DEBUG
int i;
#endif
if (rcode) {
DPRINTF(("Bad return code: %d\n", rcode));
if (ab->ab_data)
free(ab->ab_data, M_1394DATA);
free(ab, M_1394DATA);
}
DPRINTF(("csr: 0x%016qx\n", (quad_t)ab->ab_csr));
for (i = 0; i < (ab->ab_retlen / 4); i++)
DPRINTF(("%d: 0x%08x\n", i, ntohl(ab->ab_data[i])));
if (ab->ab_csr == SBP2_LOGIN_RESP) {
devcap->dev_valid |= 0x01;
devcap->dev_spec = ntohl(ab->ab_data[0]) & 0xffff;
devcap->dev_cmdptr =
(((u_int64_t)(ntohl(ab->ab_data[1]) & 0xfff)) << 32) +
ntohl(ab->ab_data[2]);
}
if (ab->ab_csr == SBP2_LOGIN_STATUS) {
status = ntohl(ab->ab_data[0]);
src = (status >> 30) & 0x3;
resp = (status >> 28) & 0x3;
dead = (status >> 27) & 0x1;
len = (status >> 24) & 0x7;
csr = ((u_int64_t)(status & 0xffff) << 32) |
ntohl(ab->ab_data[1]);
status = (status >> 16) & 0xff;
DPRINTF(("status -- src: %d, resp: %d, dead: %d, len: %d, "
"status: %d\nstatus -- csr: 0x%016qx\n", src, resp, dead,
(len + 1) * 4, status, (quad_t)csr));
if ((src == 0) && (resp == 0) && (dead == 0) && (status == 0) &&
(csr == SBP2_LOGIN_ORB)) {
devcap->dev_valid |= 0x02;
DPRINTF(("Got a valid status\n"));
}
}
if (devcap->dev_valid == 0x3) {
devcap->name = "fwscsi";
sc->sc_child = config_found(&sc->sc_sc1394.sc1394_dev, devcap,
fwnode_print);
}
/*
* Leave the handler for status since unsolicited status will get sent
* to the addr specified in the login packet.
*/
if (ab->ab_csr == SBP2_LOGIN_RESP) {
sc->sc1394_unreg(ab, TRUE);
free(ab->ab_data, M_1394DATA);
free(ab, M_1394DATA);
}
}