From nobody Mon Oct 27 13:50:41 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=kernel.org ARC-Seal: i=1; a=rsa-sha256; t=1761409382; cv=none; d=zohomail.com; s=zohoarc; b=Ik7IeNHuDSCGgUVkQWG07MCxO+3491BcVGvOrQJvlxcjB7T+oC4n1ye3pnaXkEL6GKcN5ZU30QCGlXr/trGpjZQwi9gHGfGkJKPFB0ecqv7WrbawNMP1CUbEPaKJ8RJxXLpMQEBOOduvJ/9tM0F/L1fhlyTuS397bxNH+VDF/uI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1761409382; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=w6KtOC6aJHTkANHKNi1LfmeGN1t6OQLhBObitc5rwWY=; b=Gx4RBGhYOd27Xl6lwJh4LUEnnA6h5lmdHCFQwusTtq3EQEGUUIi2hDap7d/H/Vx0+n+ANvWaTqJ8OurOUC7ayHxplcASRUyu9M9lGklBzKE3VLQfBvYmwN02BLtCd2I0MJUjvJOqjr6g+Boa0xLEghzmocW5rDfhaPF8K3c3yZM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1761409382153110.44793655145997; Sat, 25 Oct 2025 09:23:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vCgzD-0004oD-G7; Sat, 25 Oct 2025 12:19:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vCgzB-0004nW-Nl for qemu-devel@nongnu.org; Sat, 25 Oct 2025 12:19:21 -0400 Received: from sea.source.kernel.org ([2600:3c0a:e001:78e:0:1991:8:25]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vCgz9-00049s-70 for qemu-devel@nongnu.org; Sat, 25 Oct 2025 12:19:21 -0400 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sea.source.kernel.org (Postfix) with ESMTP id B239040B5F; Sat, 25 Oct 2025 16:19:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAA61C116C6; Sat, 25 Oct 2025 16:19:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1761409150; bh=D/ZHEbgaMlKUFGet457khYnQ7gpazEoXuF0X4RvvnCA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sfJ01SBlegMZt7s/5ve637wqwEaQaXx4z51oFCKCA7gAJk+NAGRqc6vGmViziejxE hkh0EvK9vchljQWKR6LwZxzitVjbHpUyqfBs6Wd5BhRAo46pBuf6AtW96WYmVkYYki sy3rW4QlPYzQ0K8cUOIXBPR8VFxDnGiGyh0VRaKvyRvJe+TaOYbV8HrlU/VC6ljwt5 G7qNX3fyoi89CIPDqYHwC+GPC3YrLmMnVuf4ZlYmYDcC3+pYmYrVofenPGS1cqSMjO p6IPs6KK309bBMgEHlbaEb9WV3NFQMjdjIEx7IGAyCg/UMzTqD7NjdASq1yUvSPMvH Ir15+t9OzW3Wg== From: deller@kernel.org To: qemu-devel@nongnu.org, Richard Henderson Cc: Fam Zheng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Soumyajyotii Ssarkar , Helge Deller , Paolo Bonzini Subject: [PATCH v2 02/11] lasi_ncr710: Add LASI wrapper for NCR 53c710 SCSI chip Date: Sat, 25 Oct 2025 18:18:52 +0200 Message-ID: <20251025161901.32710-3-deller@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251025161901.32710-1-deller@kernel.org> References: <20251025161901.32710-1-deller@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2600:3c0a:e001:78e:0:1991:8:25; envelope-from=deller@kernel.org; helo=sea.source.kernel.org X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @kernel.org) X-ZM-MESSAGEID: 1761409382660158500 Content-Type: text/plain; charset="utf-8" From: Soumyajyotii Ssarkar The LASI multi I/O chip in older PA-RISC machines includes a SCSI core based on the NCR 53c710 SCSI chip. This driver adds the glue code to talk to the NCR710 via LASI. This driver was developed as part of the Google Summer of Code 2025 program. Signed-off-by: Soumyajyotii Ssarkar Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- MAINTAINERS | 1 + hw/scsi/lasi_ncr710.c | 282 ++++++++++++++++++++++++++++++++++++++++++ hw/scsi/lasi_ncr710.h | 57 +++++++++ hw/scsi/trace-events | 17 +++ 4 files changed, 357 insertions(+) create mode 100644 hw/scsi/lasi_ncr710.c create mode 100644 hw/scsi/lasi_ncr710.h diff --git a/MAINTAINERS b/MAINTAINERS index 84cfd85e1f..a204c38754 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1283,6 +1283,7 @@ F: hw/net/*i82596* F: hw/misc/lasi.c F: hw/pci-host/astro.c F: hw/pci-host/dino.c +F: hw/scsi/lasi_ncr710.* F: include/hw/input/lasips2.h F: include/hw/misc/lasi.h F: include/hw/net/lasi_82596.h diff --git a/hw/scsi/lasi_ncr710.c b/hw/scsi/lasi_ncr710.c new file mode 100644 index 0000000000..b674a4066f --- /dev/null +++ b/hw/scsi/lasi_ncr710.c @@ -0,0 +1,282 @@ +/* + * LASI Wrapper for NCR710 SCSI Controller + * + * Copyright (c) 2025 Soumyajyotii Ssarkar + * This driver was developed during the Google Summer of Code 2025 program. + * Mentored by Helge Deller + * + * NCR710 SCSI Controller implementation + * Based on the NCR53C710 Technical Manual Version 3.2, December 2000 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/scsi/lasi_ncr710.h" +#include "hw/scsi/ncr53c710.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "qemu/log.h" +#include "trace.h" +#include "system/blockdev.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "system/dma.h" + +#define LASI_710_SVERSION 0x00082 +#define SCNR 0xBEEFBABE +#define LASI_710_HVERSION 0x3D +#define HPHW_FIO 5 /* Fixed I/O module */ + +static uint64_t lasi_ncr710_reg_read(void *opaque, hwaddr addr, + unsigned size) +{ + LasiNCR710State *s =3D LASI_NCR710(opaque); + uint64_t val =3D 0; + + trace_lasi_ncr710_reg_read(addr, 0, size); + + if (addr =3D=3D 0x00) { /* Device ID */ + val =3D (HPHW_FIO << 24) | LASI_710_SVERSION; + trace_lasi_ncr710_reg_read_id(HPHW_FIO, LASI_710_SVERSION, val); + return val; + } + + if (addr =3D=3D 0x08) { /* HVersion */ + val =3D LASI_710_HVERSION; + trace_lasi_ncr710_reg_read_hversion(val); + return val; + } + + if (addr >=3D 0x100) { + hwaddr ncr_addr =3D addr - 0x100; + if (size =3D=3D 1) { + ncr_addr ^=3D 3; + NCR710_DPRINTF("Reading value to LASI WRAPPER =3D=3D 0x%lx%s, " + "val=3D0x%lx, size=3D%u\n", + addr - 0x100, size =3D=3D 1 ? " (XORed)" : "", + val, size); + val =3D ncr710_reg_read(&s->ncr710, ncr_addr, size); + } else { + val =3D 0; + for (unsigned i =3D 0; i < size; i++) { + uint8_t byte_val =3D ncr710_reg_read(&s->ncr710, ncr_addr = + i, 1); + val |=3D ((uint64_t)byte_val) << (i * 8); + NCR710_DPRINTF(" Read byte %u from NCR addr 0x%lx: " + "0x%02x\n", i, ncr_addr + i, byte_val); + } + NCR710_DPRINTF(" Reconstructed %u-byte value: 0x%lx\n", + size, val); + } + + trace_lasi_ncr710_reg_forward_read(addr, val); + } else { + val =3D 0; + trace_lasi_ncr710_reg_read(addr, val, size); + } + return val; +} + +static void lasi_ncr710_reg_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + LasiNCR710State *s =3D LASI_NCR710(opaque); + + trace_lasi_ncr710_reg_write(addr, val, size); + + if (addr <=3D 0x0F) { + return; + } + + if (addr >=3D 0x100) { + hwaddr ncr_addr =3D addr - 0x100; + + if (size =3D=3D 1) { + ncr_addr ^=3D 3; + NCR710_DPRINTF("Writing value to LASI WRAPPER =3D=3D 0x%lx%s, " + "val=3D0x%lx, size=3D%u\n", + addr - 0x100, size =3D=3D 1 ? " (XORed)" : "", + val, size); + ncr710_reg_write(&s->ncr710, ncr_addr, val, size); + } else { + for (unsigned i =3D 0; i < size; i++) { + uint8_t byte_val =3D (val >> (i * 8)) & 0xff; + NCR710_DPRINTF(" Writing byte %u to NCR addr 0x%lx: 0x%0= 2x\n", + i, ncr_addr + i, byte_val); + ncr710_reg_write(&s->ncr710, ncr_addr + i, byte_val, 1); + } + } + + trace_lasi_ncr710_reg_forward_write(addr, val); + } else { + trace_lasi_ncr710_reg_write(addr, val, size); + } +} + +/* + * req_cancelled, command_complete, transfer_data forwards + * commands to its core counterparts. + */ +static void lasi_ncr710_request_cancelled(SCSIRequest *req) +{ + trace_lasi_ncr710_request_cancelled(req); + ncr710_request_cancelled(req); +} + +static void lasi_ncr710_command_complete(SCSIRequest *req, size_t resid) +{ + trace_lasi_ncr710_command_complete(req->status, resid); + ncr710_command_complete(req, resid); +} + + static void lasi_ncr710_transfer_data(SCSIRequest *req, uint32_t len) +{ + trace_lasi_ncr710_transfer_data(len); + ncr710_transfer_data(req, len); +} + +static const struct SCSIBusInfo lasi_ncr710_scsi_info =3D { + .tcq =3D true, + .max_target =3D 8, + .max_lun =3D 8, /* full LUN support */ + + .transfer_data =3D lasi_ncr710_transfer_data, + .complete =3D lasi_ncr710_command_complete, + .cancel =3D lasi_ncr710_request_cancelled, +}; + +static const MemoryRegionOps lasi_ncr710_mmio_ops =3D { + .read =3D lasi_ncr710_reg_read, + .write =3D lasi_ncr710_reg_write, + .endianness =3D DEVICE_BIG_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static const VMStateDescription vmstate_lasi_ncr710 =3D { + .name =3D "lasi-ncr710", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static void lasi_ncr710_realize(DeviceState *dev, Error **errp) +{ + LasiNCR710State *s =3D LASI_NCR710(dev); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + + trace_lasi_ncr710_device_realize(); + + scsi_bus_init(&s->ncr710.bus, sizeof(s->ncr710.bus), dev, + &lasi_ncr710_scsi_info); + s->ncr710.as =3D &address_space_memory; + s->ncr710.irq =3D s->lasi_irq; + + s->ncr710.reselection_retry_timer =3D + timer_new_ns(QEMU_CLOCK_VIRTUAL, + ncr710_reselection_retry_callback, + &s->ncr710); + + ncr710_soft_reset(&s->ncr710); + + trace_lasi_ncr710_timers_initialized( + (uint64_t)s->ncr710.reselection_retry_timer); + + /* Initialize memory region */ + memory_region_init_io(&s->mmio, OBJECT(dev), &lasi_ncr710_mmio_ops, s, + "lasi-ncr710", 0x200); + sysbus_init_mmio(sbd, &s->mmio); +} + +void lasi_ncr710_handle_legacy_cmdline(DeviceState *lasi_dev) +{ + LasiNCR710State *s =3D LASI_NCR710(lasi_dev); + SCSIBus *bus =3D &s->ncr710.bus; + int found_drives =3D 0; + + if (!bus) { + return; + } + + for (int unit =3D 0; unit <=3D 7; unit++) { + DriveInfo *dinfo =3D drive_get(IF_SCSI, bus->busnr, unit); + if (dinfo) { + trace_lasi_ncr710_legacy_drive_found(bus->busnr, unit); + found_drives++; + } + } + + trace_lasi_ncr710_handle_legacy_cmdline(bus->busnr, found_drives); + + scsi_bus_legacy_handle_cmdline(bus); + BusChild *kid; + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + trace_lasi_ncr710_scsi_device_created( + object_get_typename(OBJECT(kid->child))); + } +} + +DeviceState *lasi_ncr710_init(MemoryRegion *addr_space, hwaddr hpa, + qemu_irq irq) +{ + DeviceState *dev; + LasiNCR710State *s; + SysBusDevice *sbd; + + dev =3D qdev_new(TYPE_LASI_NCR710); + s =3D LASI_NCR710(dev); + sbd =3D SYS_BUS_DEVICE(dev); + s->lasi_irq =3D irq; + sysbus_realize_and_unref(sbd, &error_fatal); + memory_region_add_subregion(addr_space, hpa, + sysbus_mmio_get_region(sbd, 0)); + return dev; +} + +static void lasi_ncr710_reset(DeviceState *dev) +{ + LasiNCR710State *s =3D LASI_NCR710(dev); + trace_lasi_ncr710_device_reset(); + ncr710_soft_reset(&s->ncr710); +} + +static void lasi_ncr710_instance_init(Object *obj) +{ + LasiNCR710State *s =3D LASI_NCR710(obj); + + s->hw_type =3D HPHW_FIO; + s->sversion =3D LASI_710_SVERSION; + s->hversion =3D LASI_710_HVERSION; +} + +static void lasi_ncr710_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->realize =3D lasi_ncr710_realize; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->fw_name =3D "scsi"; + dc->desc =3D "HP-PARISC LASI NCR710 SCSI adapter"; + device_class_set_legacy_reset(dc, lasi_ncr710_reset); + dc->vmsd =3D &vmstate_lasi_ncr710; + dc->user_creatable =3D false; +} + +static const TypeInfo lasi_ncr710_info =3D { + .name =3D TYPE_LASI_NCR710, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(LasiNCR710State), + .instance_init =3D lasi_ncr710_instance_init, + .class_init =3D lasi_ncr710_class_init, +}; + +static void lasi_ncr710_register_types(void) +{ + type_register_static(&lasi_ncr710_info); +} + +type_init(lasi_ncr710_register_types) diff --git a/hw/scsi/lasi_ncr710.h b/hw/scsi/lasi_ncr710.h new file mode 100644 index 0000000000..3711233b0f --- /dev/null +++ b/hw/scsi/lasi_ncr710.h @@ -0,0 +1,57 @@ +/* + * LASI Wrapper for NCR710 SCSI Controller + * + * Copyright (c) 2025 Soumyajyotii Ssarkar + * This driver was developed during the Google Summer of Code 2025 program. + * Mentored by Helge Deller + * + * NCR710 SCSI Controller implementation + * Based on the NCR53C710 Technical Manual Version 3.2, December 2000 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_LASI_NCR710_H +#define HW_LASI_NCR710_H + +#include "hw/sysbus.h" +#include "qemu/osdep.h" +#include "exec/memattrs.h" +#include "hw/scsi/scsi.h" +#include "hw/scsi/ncr53c710.h" + +#define TYPE_LASI_NCR710 "lasi-ncr710" +OBJECT_DECLARE_SIMPLE_TYPE(LasiNCR710State, LASI_NCR710) + +#define LASI_SCSI_RESET 0x000 /* SCSI Reset Register */ +#define LASI_SCSI_NCR710_BASE 0x100 /* NCR710 Base Register Offset */ + +#define PARISC_DEVICE_ID_OFF 0x00 /* HW type, HVERSION, SVERSION */ +#define PARISC_DEVICE_CONFIG_OFF 0x04 /* Configuration data */ + +#define PHASE_MASK 7 +#define PHASE_DO 0 + +#define NCR710_SCNTL1_RST 0x08 /* SCSI Reset */ +#define NCR710_ISTAT_RST 0x40 /* Device Reset */ +#define NCR710_ISTAT_ABRT 0x80 /* Script Abort */ +#define NCR710_ISTAT_CON 0x08 /* ISTAT_Connected */ +#define NCR710_DSTAT_DFE 0x80 /* DMA FIFO Empty */ +#define NCR710_CTEST2_DACK 0x01 /* DMA Acknowledge */ + +typedef struct LasiNCR710State { + SysBusDevice parent_obj; + MemoryRegion mmio; + qemu_irq lasi_irq; /* IRQ line to LASI controller */ + uint32_t hw_type; /* Hardware type (HPHW_*) */ + uint32_t sversion; /* Software version */ + uint32_t hversion; /* Hardware version */ + SCSIBus bus; + NCR710State ncr710; +} LasiNCR710State; + +DeviceState *lasi_ncr710_init(MemoryRegion *addr_space, hwaddr hpa, + qemu_irq irq); +void lasi_ncr710_handle_legacy_cmdline(DeviceState *lasi_dev); + +#endif diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 6c2788e202..0604050a67 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -306,6 +306,23 @@ lsi_reg_write(const char *name, int offset, uint8_t va= l) "Write reg %s 0x%x =3D 0x lsi_scripts_timer_triggered(void) "SCRIPTS timer triggered" lsi_scripts_timer_start(void) "SCRIPTS timer started" =20 +# lasi_ncr710.c +lasi_ncr710_device_realize(void) "Device realized" +lasi_ncr710_device_reset(void) "Device reset" +lasi_ncr710_reg_read(uint32_t addr, uint32_t val, unsigned size) "addr=3D0= x%03x val=3D0x%08x size=3D%u" +lasi_ncr710_reg_write(uint32_t addr, uint32_t val, unsigned size) "addr=3D= 0x%03x val=3D0x%08x size=3D%u" +lasi_ncr710_reg_read_id(uint32_t hw_type, uint32_t sversion, uint32_t val)= "hw_type=3D%u sversion=3D0x%04x val=3D0x%08x" +lasi_ncr710_reg_read_hversion(uint32_t hversion) "LASI NCR710: HVersion re= ad -> 0x%02x" +lasi_ncr710_reg_forward_read(uint32_t addr, uint32_t val) "LASI NCR710: Fo= rward read to NCR710 core addr=3D0x%03x val=3D0x%08x" +lasi_ncr710_reg_forward_write(uint32_t addr, uint32_t val) "LASI NCR710: F= orward write to NCR710 core addr=3D0x%03x val=3D0x%08x" +lasi_ncr710_command_complete(uint32_t status, size_t resid) "LASI NCR710: = Command complete status=3D0x%02x resid=3D%zu" +lasi_ncr710_transfer_data(uint32_t len) "LASI NCR710: Transfer data len=3D= %u" +lasi_ncr710_request_cancelled(void *req) "LASI NCR710: Request cancelled r= eq=3D%p" +lasi_ncr710_timers_initialized(uint64_t reselection) "Timers: reselection= =3D0x%" PRIx64 +lasi_ncr710_handle_legacy_cmdline(int busnr, int found_drives) "LASI NCR71= 0: Handle legacy cmdline busnr=3D%d found_drives=3D%d" +lasi_ncr710_legacy_drive_found(int busnr, int unit) "LASI NCR710: Found le= gacy drive at bus=3D%d unit=3D%d" +lasi_ncr710_scsi_device_created(const char *type) "LASI NCR710: SCSI devic= e created: %s" + # virtio-scsi.c virtio_scsi_cmd_req(int lun, uint32_t tag, uint8_t cmd) "virtio_scsi_cmd_r= eq lun=3D%u tag=3D0x%x cmd=3D0x%x" virtio_scsi_cmd_resp(int lun, uint32_t tag, int response, uint8_t status) = "virtio_scsi_cmd_resp lun=3D%u tag=3D0x%x response=3D%d status=3D0x%x" --=20 2.51.0